Plugin Directory

Changeset 2468562


Ignore:
Timestamp:
02/04/2021 08:47:27 AM (4 years ago)
Author:
laterpay
Message:

Version 2.0.1

Location:
revenue-generator
Files:
4 added
26 deleted
35 edited
11 copied

Legend:

Unmodified
Added
Removed
  • revenue-generator/tags/2.0.1/languages/revenue-generator.po

    r2466307 r2468562  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Revenue Generator 2.0.0\n"
     5"Project-Id-Version: Revenue Generator 2.0.1\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/revenue-generator\n"
    77"Last-Translator: Kimberly Moore <[email protected]>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2021-02-01T09:02:16+00:00\n"
     12"POT-Creation-Date: 2021-02-04T08:24:31+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.4.0\n"
     
    403403
    404404#: v1/inc/classes/class-frontend-post.php:780
    405 #: v2/inc/classes/class-frontend-post.php:194
     405#: v2/inc/classes/class-frontend-post.php:191
    406406msgid "Contribution amount cannot be empty."
    407407msgstr ""
     
    13571357
    13581358#: v1/templates/frontend/contribution/partial-custom.php:35
    1359 #: v2/templates/frontend/contribution/partial-amounts.php:71
     1359#: v2/templates/frontend/contribution/partial-amounts.php:98
    13601360msgid "Enter custom amount"
    13611361msgstr ""
     
    13661366
    13671367#: v1/templates/frontend/contribution/partial-donate.php:37
    1368 #: v2/templates/frontend/contribution/partial-amounts.php:62
     1368#: v2/templates/frontend/contribution/partial-amounts.php:89
    13691369msgid "Custom"
    13701370msgstr ""
    13711371
    1372 #: v2/inc/classes/class-frontend-post.php:201
     1372#: v2/inc/classes/class-frontend-post.php:198
    13731373msgid "Contribution details cannot be empty."
    13741374msgstr ""
     
    14311431msgstr ""
    14321432
    1433 #: v2/templates/frontend/contribution/partial-amounts.php:72
     1433#: v2/templates/frontend/contribution/partial-amounts.php:99
    14341434msgid "Send"
    14351435msgstr ""
    14361436
    1437 #: v2/templates/frontend/contribution/partial-amounts.php:76
     1437#: v2/templates/frontend/contribution/partial-amounts.php:103
    14381438msgid "Add to MyTab"
    14391439msgstr ""
  • revenue-generator/tags/2.0.1/readme.txt

    r2466307 r2468562  
    77Tested up to: 5.6
    88Requires PHP: 5.6
    9 Stable tag: 2.0.0
     9Stable tag: 2.0.1
    1010Author URI: https://laterpay.net
    1111Plugin URI: https://github.com/laterpay/revenue-generator/
     
    8282== Changelog ==
    8383
     84= 2.0.1 ( 4 February 2021 ) =
     85* Fixed issue with contributions on page cache enabled hosts.
     86
    8487= 2.0.0 ( 1 February 2021 ) =
    8588* New for contributions-only merchants: on-page purchase and payment experience powered by all new Laterpay platform.
     
    126129== Upgrade notice ==
    127130
     131= 2.0.1 =
     132Fixed issue with contributions on page cache enabled hosts.
     133
    128134= 2.0.0 =
    129135New on-page purchase and payment experience for contributions-only merchants. Added support for custom post types to paywalls.
  • revenue-generator/tags/2.0.1/revenue-generator.php

    r2466307 r2468562  
    44 * Description: Monetize your blog and content with Laterpay's Revenue Generator.
    55 * Plugin URI: https://github.com/laterpay/revenue-generator
    6  * Version: 2.0.0
     6 * Version: 2.0.1
    77 * Author: Laterpay
    88 * Text Domain: revenue-generator
     
    1515defined( 'ABSPATH' ) || exit;
    1616
    17 define( 'REVENUE_GENERATOR_VERSION', '2.0.0' );
     17define( 'REVENUE_GENERATOR_VERSION', '2.0.1' );
    1818
    1919if ( ! defined( 'REVENUE_GENERATOR_PLUGIN_FILE' ) ) {
  • revenue-generator/tags/2.0.1/v2/assets/build/css/frontend.css

    r2466307 r2468562  
    1 .amount-text,.rev-gen-contribution__amount{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:600;line-height:1.21;text-align:center;color:#333}.rev-gen-contribution{position:relative;width:100%;margin:20px auto;height:auto;transition:height 0.2s ease-in}.rev-gen-contribution__inner{position:relative;height:100%;padding:18px 25px;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:250px}.rev-gen-contribution__question-mark,.rev-gen-contribution-info-modal__x-mark{position:absolute;top:10px;right:10px;z-index:20;cursor:pointer;width:18px;height:18px;border-radius:50%;font-weight:700;font-size:12px;background-color:#1d1d1d;color:#fff;text-align:center}.rev-gen-contribution__question-mark span,.rev-gen-contribution-info-modal__x-mark span{position:relative;left:1px}.rev-gen-contribution-modal .rev-gen-contribution__question-mark,.rev-gen-contribution-modal .rev-gen-contribution-info-modal__x-mark{top:13px;right:35px}.rev-gen-contribution-info-modal{position:absolute;top:0;left:0;z-index:50;padding:20px;border-radius:5px;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution-info-modal__x-mark span{position:relative;top:-1px}.rev-gen-contribution-info-modal__title{margin:0;font-weight:500;font-size:18px}.rev-gen-contribution-info-modal__steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.rev-gen-contribution-info-modal__step{display:flex;align-items:center;margin:0;font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__step-text{margin-left:6px;margin-right:10px}.rev-gen-contribution-info-modal__step-number{display:flex;align-items:center;justify-content:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.rev-gen-contribution-info-modal__description{font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__description p{margin-bottom:1em}.rev-gen-contribution-info-modal__description p:last-child{margin-bottom:0}.rev-gen-contribution h2.rev-gen-contribution__title{margin:0;max-width:100%;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:bold;line-height:1.33;font-size:21px;text-align:center;color:#1d1d1d}.rev-gen-contribution h2.rev-gen-contribution__title::before,.rev-gen-contribution h2.rev-gen-contribution__title::after{display:none !important}.rev-gen-contribution__description{max-width:100%;font-size:14px;text-align:center}.rev-gen-contribution__amounts{display:flex;flex-flow:row nowrap;justify-content:space-between;margin-bottom:20px}.rev-gen-contribution--bar .rev-gen-contribution__amounts{justify-content:center}.rev-gen-contribution__form{margin:20px 0}.rev-gen-contribution__form.amp-form-submit-success,.rev-gen-contribution__form.amp-form-submit-error{margin:0}.rev-gen-contribution__form button[type="submit"]{max-width:100%;flex:0 1 100%;width:100%;padding:15px 0;font-size:15px;border:1px solid #000;border-radius:4px;font-weight:500;background:#1d1d1d !important;color:#fff !important;text-decoration:none;text-transform:none;text-shadow:none}.rev-gen-contribution__form button[type="submit"].show{display:block}.rev-gen-contribution .rev-gen-hidden{display:none}.rev-gen-contribution__amount{min-width:75px;border:solid 2px #1d1d1d;border-radius:5px;margin:0 2px;display:flex;align-items:center;text-align:center;justify-content:center;overflow:hidden;cursor:pointer;word-break:normal;color:#1d1d1d;background-color:#fff}.rev-gen-contribution__amount input{position:absolute;opacity:0;width:0;height:0}.rev-gen-contribution__amount--custom{outline:0;text-transform:none;text-decoration:none}.rev-gen-contribution__amount--custom:hover,.rev-gen-contribution__amount--custom:active,.rev-gen-contribution__amount--custom:focus{background:#1d1d1d !important;color:#fff !important;text-decoration:none}.rev-gen-contribution__amount .rev-gen-contribution-control__label{display:block;width:100%;height:100%;border:0;padding:15px;font-size:14px;background:#fff !important;color:#1d1d1d !important;box-shadow:none !important;transition:background-color 0.05s ease-in !important;text-decoration:none !important;text-transform:none !important;letter-spacing:0 !important}.rev-gen-contribution__amount .rev-gen-contribution-control__label:hover{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount input:checked+.rev-gen-contribution-control__label{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount-wrapper{position:relative;display:flex;justify-content:center}.rev-gen-contribution__tip{margin:0 0 5px;line-height:1;font-size:13px;text-align:center}.rev-gen-contribution__tip.rev-gen-hidden{visibility:hidden}.rev-gen-contribution__custom input[type="number"]{min-width:220px;margin-right:5px;padding:13.5px 0 13px 15px;border-radius:5px;background-color:rgba(160,160,160,0.12);margin-bottom:10px;font-size:14px;outline:0;border:0}.rev-gen-contribution__custom.rev-gen-hidden:not[hidden]{display:none}.rev-gen-contribution__tab-status{height:100%;font-size:14px;text-align:center;transition:min-height 0.2s ease-in}.rev-gen-contribution__tab-status iframe{width:100%;height:0;margin:0 !important;padding:0 !important;border:0 !important}.rev-gen-contribution__response{position:relative;z-index:2;width:100%;background-color:#fff}.rev-gen-contribution__loading{position:absolute;z-index:1;top:50%;margin-top:-32px;left:50%;margin-left:-38px}.rev-gen-contribution-custom{max-width:335px;margin:10px auto;display:flex;flex-flow:row nowrap;align-items:center}.rev-gen-contribution-custom__group{flex:1;display:flex;flex-flow:row nowrap}.rev-gen-contribution-custom__inner{display:flex;flex-flow:row nowrap;align-items:flex-end;justify-content:space-between}.rev-gen-contribution-custom__form{display:flex;align-items:flex-end}.rev-gen-contribution-custom h3.rev-gen-contribution-custom__title{margin:0;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;line-height:1.33;font-size:14px;color:#1d1d1d}.rev-gen-contribution-custom__back{position:relative;bottom:5px;float:left;cursor:pointer;width:15px;margin-right:15px}.rev-gen-contribution-custom__back-arrow{display:inline-block;vertical-align:middle;border:solid #000;border-width:0 2px 2px 0;padding:14px;transform:rotate(135deg)}.rev-gen-contribution-custom__symbol{width:15px;text-align:center}.rev-gen-contribution-custom label{display:block;margin-left:15px;margin-bottom:5px;line-height:1;font-weight:normal;font-size:12px}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send{flex:1;width:auto;min-width:70px;max-width:none;max-height:49px;margin:0;padding:14px 10px !important;border:2px solid #1d1d1d !important;border-radius:5px;font-weight:700;font-size:14px;color:#1d1d1d !important;background-color:#fff !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:active,.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:hover{color:#fff !important;background-color:#1d1d1d !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:disabled{opacity:0.8}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send .rev-gen-contribution-custom-send__loading{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading{padding:11px 10px !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__text{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__loading{display:inline-block;width:21px;height:21px;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMiIgYmFzZVByb2ZpbGU9InRpbnkiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgoJIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTAwIDUwMCIgb3ZlcmZsb3c9InZpc2libGUiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGZpbGw9IiNmZmZmZmYiIGQ9Ik0zMTcsNDc5LjRjLTEyLDAtMjMuMy03LjYtMjcuNC0xOS42Yy01LjItMTUuMSwyLjktMzEuNiwxOC0zNi44YzcxLjUtMjQuNiwxMTkuNS05MS45LDExOS41LTE2Ny41CgkJYzAtOTcuNi03OS40LTE3Ny4xLTE3Ny4xLTE3Ny4xUzcyLjksMTU3LjksNzIuOSwyNTUuNmMwLDc1LjYsNDgsMTQzLDExOS41LDE2Ny41YzE1LjEsNS4yLDIzLjIsMjEuNywxOCwzNi44cy0yMS43LDIzLjItMzYuOCwxOAoJCUM3OC43LDQ0NS4zLDE1LDM1NS45LDE1LDI1NS42YzAtMTI5LjYsMTA1LjQtMjM1LDIzNS0yMzVzMjM1LDEwNS40LDIzNSwyMzVjMCwxMDAuNC02My43LDE4OS43LTE1OC42LDIyMi4zCgkJQzMyMy4zLDQ3OC45LDMyMC4xLDQ3OS40LDMxNyw0NzkuNHoiLz4KPC9nPgo8L3N2Zz4K) no-repeat;background-size:21px 21px;transition:transform 0.2s ease-in-out;-webkit-animation:pulse-loading 1s infinite;animation:pulse-loading 1s infinite}.rev-gen-contribution-footer{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif}.rev-gen-contribution-footer__inner{display:flex;align-items:center;justify-content:center}.rev-gen-contribution-footer a{flex:1;margin-left:5px;max-width:75px;opacity:0.6;transition:opacity 0.2s ease-in}.rev-gen-contribution-footer a:hover{opacity:1}.rev-gen-contribution-footer a img{vertical-align:middle}.rev-gen-contribution-footer span{position:relative;top:2px;line-height:1.1;font-size:11px;color:#808080}.rev-gen-contribution--box{max-width:380px !important}.rev-gen-contribution--bar{width:100%}.rev-gen-contribution--bar .rev-gen-contribution__donate{margin:15px 0 5px}.rev-gen-contribution--bar .rev-gen-contribution__inner{max-width:100%;padding:15px 25px}.rev-gen-contribution--bar.size-large h2.rev-gen-contribution__title{min-width:250px;margin-right:15px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__inner{padding:0 25px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__choose{display:flex;align-items:center}.rev-gen-contribution--bar.size-large .rev-gen-contribution__description{min-width:250px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form{margin:15px 0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form button[type="submit"]{width:300px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__amounts{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__donate{align-self:flex-end;margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-info-modal{left:auto;right:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom{margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom label{display:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom__back{bottom:auto;float:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom input[type="number"]{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom button[type="submit"]{width:auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution__loading{transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response{display:flex;align-items:center;transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response .tab_widget__container{height:85px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer{margin-left:15px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer a{width:75px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__tab-status{position:relative;min-width:250px;height:85px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__loading{left:0;margin-left:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__response{height:100%;overflow:hidden;margin-right:10px;transform:none;background-color:transparent}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution iframe{height:85px !important}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution-footer{display:none}.rev-gen-contribution--bar.size-large.amount-selected .rev-gen-contribution__amounts{display:none}.rev-gen-contribution--bar.size-large.rev-gen-iframe-ready iframe{width:600px}.rev-gen-contribution--button .rev-gen-contribution__inner{padding:0;box-shadow:none;background-color:transparent;text-align:center}.rev-gen-contribution--button .rev-gen-contribution__footer{margin-top:15px}.rev-gen-contribution--button .rev-gen-contribution__button{max-width:320px;padding:15px 30px;border:0;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:16px;color:#fff;background-color:#1d1d1d;text-decoration:none}.rev-gen-contribution--button .rev-gen-contribution__button:hover,.rev-gen-contribution--button .rev-gen-contribution__button:active{border:0;box-shadow:none;text-decoration:none}.rev-gen-contribution--button:not(.is-amp) .rev-gen-contribution-modal{display:none}.rev-gen-contribution.is-amp iframe{position:relative;z-index:15}.rev-gen-contribution .amp-form-submit-success>*{display:none}.rev-gen-contribution .amp-form-submitting{height:100px}.rev-gen-contribution__amp-show-modal,.rev-gen-contribution__amp-show-modal--purchase{position:absolute;bottom:35px;left:165px;z-index:10;width:95px;height:20px;display:block;background:transparent;cursor:pointer}.rev-gen-contribution__amp-show-modal--purchase{top:72px;bottom:auto}.rev-gen-contribution-modal{position:fixed;top:0;left:0;z-index:9999;display:flex;align-items:center;width:100%;height:100%;background-color:rgba(0,0,0,0.5);opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution{opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution__inner{padding:30px 25px 18px;background-color:#fff}.rev-gen-contribution-modal.active{opacity:1}.rev-gen-contribution-modal.active .rev-gen-contribution{opacity:1}.rev-gen-contribution-modal__close{position:absolute;top:15px;right:15px;display:inline-block;width:15px;height:15px;padding:0 !important;border:0 !important;background:transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMyIgaGVpZ2h0PSIxMyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDEzIDEzIj4KICAgIDxwYXRoIGZpbGw9IiMxRDFEMUQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTguMDMyIDYuNUwxMyAxLjUzMSAxMS40NjggMCA2LjUgNC45NjggMS41MzIgMCAwIDEuNTMybDQuOTY4IDQuOTY3TDAgMTEuNDY3bDEuNTMyIDEuNTMyTDYuNSA4LjAzbDQuOTY4IDQuOTY4TDEzIDExLjQ2NyA4LjAzMiA2LjQ5OXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPgo8L3N2Zz4K) no-repeat !important;background-size:15px 15px !important;opacity:0.35}.is-amp .rev-gen-contribution-modal{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution-amp-wrap{display:flex;width:100%;height:100%;align-items:center}@-webkit-keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}.font,.tab_widget__donated-amount-text,.tab_widget__thank-you-message,.tab_widget__regular-text,.tab_widget__link,.tab__widget__info-button-question-mark,.tab_widget__info_container{font-family:"Helvetica Neue", Arial, Helvetica, sans-serif}.tab_widget{display:flex;justify-content:center;align-items:center;height:100%}.tab_widget__container{position:relative;background-color:#fff;border-radius:6px;display:flex;align-items:center;width:340px;height:104px;transition:transform 0.5s linear}.tab_widget__container-visible{transform:translate(0)}.tab_widget__arc-container{margin-right:6px;width:calc(64px + 6px);height:64px;position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:center}.tab_widget__arc--background{position:absolute;stroke:#cbd5e0}.tab_widget__arc--filled{position:absolute;stroke:#000;stroke-dasharray:175.84;stroke-dashoffset:175.84}.tab_widget__arc-animation{-webkit-animation:animateTabAmount 0.5s linear forwards;animation:animateTabAmount 0.5s linear forwards}.tab_widget__arc-animation--pulse{stroke:#000;animation:pulse 1s ease-in-out alternate-reverse infinite}.tab_widget__arc-animation--pulse circle{stroke:#000;stroke-opacity:inherit}@-webkit-keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@-webkit-keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}@keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}.tab_widget__donated-amount-text{font-weight:700}.tab_widget__thank-you-message{font-weight:500;margin:0;margin-bottom:5px;font-size:19px;color:#1d1d1d;text-align:left}.tab_widget__regular-text{font-weight:400;font-size:15px;margin:0;margin-bottom:5px;color:#333}.tab_widget__links-container{display:flex;align-items:center}.tab_widget__link{font-weight:400;margin:0;font-size:13px;color:#1d1d1d;text-decoration:underline;cursor:pointer}.tab_widget__links-separator{padding-right:5px;padding-left:5px;color:#333}.tab_widget__container-hidden{transform:translate(500px)}.tab__widget__info-button__container{position:absolute;right:6px;top:6px;cursor:pointer}.tab__widget__info-button{position:relative}.tab__widget__info-button-question-mark{position:absolute;font-weight:700;font-size:12px;color:#fff;left:34%;top:0}.tab__widget__close-button-x-mark{left:33%;top:-1px}.tab_widget__container__info-screen{position:absolute;height:100%;width:calc(100% + 50px);margin-top:-35px;margin-left:-25px;z-index:10;visibility:var(--infoScreenVisibility);text-align:left}.tab_widget__info_container{position:relative;padding:20px;background-color:#fff;box-shadow:0 1px 8px 0 rgba(29,29,29,0.16);border-radius:6px}.tab_widget__info-title{font-weight:500;font-size:18px;margin:0}.tab_widget__info-steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.tab_widget__info-step{display:flex;align-items:center;font-weight:500;font-size:14px;margin:0}.tab_widget__info-step-text{margin-left:6px;margin-right:10px}.tab_widget__info-step-number{display:flex;justify-content:center;align-items:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.tab_widget__info-description{font-weight:500;font-size:14px}.tab_widget__info-description p{margin-bottom:1em}.tab_widget__info-description p:last-child{margin-bottom:0}.tab__widget__icon{position:unset;height:18px;width:18px}
     1.amount-text,.rev-gen-contribution__amount{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:600;line-height:1.21;text-align:center;color:#333}.rev-gen-contribution{position:relative;width:100%;margin:20px auto;height:auto;transition:height 0.2s ease-in}.rev-gen-contribution__inner{position:relative;height:100%;padding:18px 25px;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:250px}.rev-gen-contribution__question-mark,.rev-gen-contribution-info-modal__x-mark{position:absolute;top:10px;right:10px;z-index:20;cursor:pointer;width:18px;height:18px;border-radius:50%;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:700;font-size:12px;background-color:#1d1d1d;color:#fff;text-align:center}.rev-gen-contribution__question-mark span,.rev-gen-contribution-info-modal__x-mark span{position:relative;left:1px}.rev-gen-contribution-modal .rev-gen-contribution__question-mark,.rev-gen-contribution-modal .rev-gen-contribution-info-modal__x-mark{top:13px;right:35px}.rev-gen-contribution-info-modal{position:absolute;top:0;left:0;z-index:50;padding:20px;border-radius:5px;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution-info-modal__x-mark span{position:relative;top:-1px}.rev-gen-contribution-info-modal__title{margin:0;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:18px}.rev-gen-contribution-info-modal__steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.rev-gen-contribution-info-modal__step{display:flex;align-items:center;margin:0;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__step-text{margin-left:6px;margin-right:10px}.rev-gen-contribution-info-modal__step-number{display:flex;align-items:center;justify-content:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.rev-gen-contribution-info-modal__description p{margin-bottom:1em;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__description p:last-child{margin-bottom:0}.rev-gen-contribution h2.rev-gen-contribution__title{margin:0;max-width:100%;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:bold;line-height:1.33;font-size:21px;text-align:center;color:#1d1d1d}.rev-gen-contribution h2.rev-gen-contribution__title::before,.rev-gen-contribution h2.rev-gen-contribution__title::after{display:none !important}.rev-gen-contribution__description{max-width:100%;font-size:14px;text-align:center}.rev-gen-contribution__amounts{display:flex;flex-flow:row nowrap;justify-content:space-between;margin-bottom:20px}.rev-gen-contribution--bar .rev-gen-contribution__amounts{justify-content:center}.rev-gen-contribution__form{margin:20px 0}.rev-gen-contribution__form.amp-form-submit-success,.rev-gen-contribution__form.amp-form-submit-error{max-height:250px;overflow:hidden;margin:0}.rev-gen-contribution__form div[submit-success]{position:relative;z-index:10}.rev-gen-contribution__form button[type="submit"]{cursor:pointer;max-width:100%;flex:0 1 100%;width:100%;padding:15px 0;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:15px;border:1px solid #000;border-radius:4px;font-weight:500;background:#1d1d1d !important;color:#fff !important;text-decoration:none;text-transform:none;text-shadow:none}.rev-gen-contribution__form button[type="submit"].show{display:block}.rev-gen-contribution .rev-gen-hidden{display:none}.rev-gen-contribution__amount{min-width:75px;border:solid 2px #1d1d1d;border-radius:5px;margin:0 2px;display:flex;align-items:center;text-align:center;justify-content:center;overflow:hidden;cursor:pointer;word-break:normal;color:#1d1d1d;background-color:#fff}.rev-gen-contribution__amount input{position:absolute;opacity:0;width:0;height:0}.rev-gen-contribution__amount--custom{outline:0;text-transform:none;text-decoration:none}.rev-gen-contribution__amount--custom:hover,.rev-gen-contribution__amount--custom:active,.rev-gen-contribution__amount--custom:focus{background:#1d1d1d !important;color:#fff !important;text-decoration:none}.rev-gen-contribution__amount .rev-gen-contribution-control__label{display:block;width:100%;height:100%;border:0;padding:15px;font-size:14px;background:#fff !important;color:#1d1d1d !important;box-shadow:none !important;transition:background-color 0.05s ease-in !important;text-decoration:none !important;text-transform:none !important;letter-spacing:0 !important}.rev-gen-contribution__amount .rev-gen-contribution-control__label:hover{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount input:checked+.rev-gen-contribution-control__label{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount-wrapper{position:relative;display:flex;justify-content:center}.rev-gen-contribution__tip{margin:0 0 5px;line-height:1;font-size:13px;text-align:center}.rev-gen-contribution__tip.rev-gen-hidden{visibility:hidden}.rev-gen-contribution__custom input[type="number"]{min-width:220px;margin:0 5px 0 0;padding:13.5px 0 13px 15px;border-radius:5px;background-color:rgba(160,160,160,0.12);font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;outline:0;border:0}.rev-gen-contribution__custom.rev-gen-hidden:not[hidden]{display:none}.rev-gen-contribution__tab-status{height:100%;font-size:14px;text-align:center;transition:min-height 0.2s ease-in}.rev-gen-contribution__tab-status iframe{width:100%;height:0;margin:0 !important;padding:0 !important;border:0 !important}.rev-gen-contribution__response{position:relative;z-index:2;width:100%;background-color:#fff}.rev-gen-contribution__loading{position:absolute;z-index:1;top:50%;margin-top:-32px;left:50%;margin-left:-38px}.rev-gen-contribution-custom{max-width:335px;margin:10px auto;display:flex;flex-flow:row nowrap;align-items:center}.rev-gen-contribution-custom__group{flex:1;display:flex;flex-flow:row nowrap}.rev-gen-contribution-custom__inner{display:flex;flex-flow:row nowrap;align-items:flex-end;justify-content:space-between}.rev-gen-contribution-custom__form{display:flex;align-items:flex-end}.rev-gen-contribution-custom h3.rev-gen-contribution-custom__title{margin:0;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;line-height:1.33;font-size:14px;color:#1d1d1d}.rev-gen-contribution-custom__back{position:relative;bottom:0;float:left;cursor:pointer;width:15px;margin-right:15px}.rev-gen-contribution-custom__back-arrow{display:inline-block;vertical-align:middle;border:solid #000;border-width:0 2px 2px 0;padding:14px;transform:rotate(135deg)}.rev-gen-contribution-custom__symbol{width:15px;text-align:center}.rev-gen-contribution-custom label{display:block;margin-left:15px;margin-bottom:5px;line-height:1;font-weight:normal;font-size:12px}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send{flex:1;width:auto;min-width:70px;max-width:none;max-height:49px;margin:0;padding:14px 10px !important;border:2px solid #1d1d1d !important;border-radius:5px;font-weight:700;font-size:14px;color:#1d1d1d !important;background-color:#fff !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:active,.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:hover{color:#fff !important;background-color:#1d1d1d !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:disabled{opacity:0.8}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send .rev-gen-contribution-custom-send__loading{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading{padding:11px 10px !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__text{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__loading{display:inline-block;width:21px;height:21px;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMiIgYmFzZVByb2ZpbGU9InRpbnkiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgoJIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTAwIDUwMCIgb3ZlcmZsb3c9InZpc2libGUiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGZpbGw9IiNmZmZmZmYiIGQ9Ik0zMTcsNDc5LjRjLTEyLDAtMjMuMy03LjYtMjcuNC0xOS42Yy01LjItMTUuMSwyLjktMzEuNiwxOC0zNi44YzcxLjUtMjQuNiwxMTkuNS05MS45LDExOS41LTE2Ny41CgkJYzAtOTcuNi03OS40LTE3Ny4xLTE3Ny4xLTE3Ny4xUzcyLjksMTU3LjksNzIuOSwyNTUuNmMwLDc1LjYsNDgsMTQzLDExOS41LDE2Ny41YzE1LjEsNS4yLDIzLjIsMjEuNywxOCwzNi44cy0yMS43LDIzLjItMzYuOCwxOAoJCUM3OC43LDQ0NS4zLDE1LDM1NS45LDE1LDI1NS42YzAtMTI5LjYsMTA1LjQtMjM1LDIzNS0yMzVzMjM1LDEwNS40LDIzNSwyMzVjMCwxMDAuNC02My43LDE4OS43LTE1OC42LDIyMi4zCgkJQzMyMy4zLDQ3OC45LDMyMC4xLDQ3OS40LDMxNyw0NzkuNHoiLz4KPC9nPgo8L3N2Zz4K) no-repeat;background-size:21px 21px;transition:transform 0.2s ease-in-out;-webkit-animation:pulse-loading 1s infinite;animation:pulse-loading 1s infinite}.rev-gen-contribution-footer{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif}.rev-gen-contribution-footer__inner{display:flex;align-items:center;justify-content:center}.rev-gen-contribution-footer a{flex:1;margin-left:5px;max-width:75px;opacity:0.6;transition:opacity 0.2s ease-in}.rev-gen-contribution-footer a:hover{opacity:1}.rev-gen-contribution-footer a img{vertical-align:middle}.rev-gen-contribution-footer span{position:relative;top:2px;line-height:1.1;font-size:11px;color:#808080}.rev-gen-contribution--box{max-width:380px !important}.rev-gen-contribution--bar{width:100%}.rev-gen-contribution--bar .rev-gen-contribution__donate{margin:15px 0 5px}.rev-gen-contribution--bar .rev-gen-contribution__inner{max-width:100%;padding:15px 25px}.rev-gen-contribution--bar.size-large h2.rev-gen-contribution__title{min-width:250px;margin-right:15px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__inner{padding:0 25px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__choose{display:flex;align-items:center}.rev-gen-contribution--bar.size-large .rev-gen-contribution__description{min-width:250px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form{margin:15px 0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form button[type="submit"]{width:300px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__amounts{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__donate{align-self:flex-end;margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-info-modal{left:auto;right:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom{margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom label{display:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom__back{bottom:auto;float:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom input[type="number"]{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom button[type="submit"]{width:auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution__loading{transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response{display:flex;align-items:center;transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response .tab_widget__container{height:85px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer{margin-left:15px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer a{width:75px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__tab-status{position:relative;min-width:250px;height:85px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__loading{left:0;margin-left:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__response{height:100%;overflow:hidden;margin-right:10px;transform:none;background-color:transparent}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution iframe{height:85px !important}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution-footer{display:none}.rev-gen-contribution--bar.size-large.amount-selected .rev-gen-contribution__amounts{display:none}.rev-gen-contribution--bar.size-large.rev-gen-iframe-ready iframe{width:600px}.rev-gen-contribution--button .rev-gen-contribution__inner{padding:0;box-shadow:none;background-color:transparent;text-align:center}.rev-gen-contribution--button .rev-gen-contribution__footer{margin-top:15px}.rev-gen-contribution--button .rev-gen-contribution__button{max-width:320px;padding:15px 30px;border:0;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:16px;color:#fff;background-color:#1d1d1d;text-decoration:none}.rev-gen-contribution--button .rev-gen-contribution__button:hover,.rev-gen-contribution--button .rev-gen-contribution__button:active{border:0;box-shadow:none;text-decoration:none}.rev-gen-contribution--button:not(.is-amp) .rev-gen-contribution-modal{display:none}.rev-gen-contribution.is-amp iframe{position:relative;z-index:15}.rev-gen-contribution .amp-form-submit-success>*{display:none}.rev-gen-contribution .amp-form-submitting{height:100px}.rev-gen-contribution__amp-show-modal,.rev-gen-contribution__amp-show-modal--purchase{position:absolute;bottom:19px;left:137px;z-index:10;width:95px;height:20px;display:block;background:transparent;cursor:pointer}.rev-gen-contribution__amp-show-modal--purchase{top:72px;bottom:auto}.rev-gen-contribution-modal{position:fixed;top:0;left:0;z-index:9999;display:flex;align-items:center;width:100%;height:100%;background-color:rgba(0,0,0,0.5);opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution{opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution__inner{padding:30px 25px 18px;background-color:#fff}.rev-gen-contribution-modal.active{opacity:1}.rev-gen-contribution-modal.active .rev-gen-contribution{opacity:1}.rev-gen-contribution-modal__close{position:absolute;top:15px;right:15px;display:inline-block;width:15px;height:15px;padding:0 !important;border:0 !important;background:transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMyIgaGVpZ2h0PSIxMyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDEzIDEzIj4KICAgIDxwYXRoIGZpbGw9IiMxRDFEMUQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTguMDMyIDYuNUwxMyAxLjUzMSAxMS40NjggMCA2LjUgNC45NjggMS41MzIgMCAwIDEuNTMybDQuOTY4IDQuOTY3TDAgMTEuNDY3bDEuNTMyIDEuNTMyTDYuNSA4LjAzbDQuOTY4IDQuOTY4TDEzIDExLjQ2NyA4LjAzMiA2LjQ5OXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPgo8L3N2Zz4K) no-repeat !important;background-size:15px 15px !important;opacity:0.35}.is-amp .rev-gen-contribution-modal{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution-amp-wrap{display:flex;width:100%;height:100%;align-items:center}@-webkit-keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}.font,.tab_widget__donated-amount-text,.tab_widget__thank-you-message,.tab_widget__regular-text,a.tab_widget__link,.tab__widget__info-button-question-mark,.tab_widget__info_container{font-family:"Helvetica Neue", Arial, Helvetica, sans-serif}.tab_widget{display:flex;justify-content:center;align-items:center;height:100%}.tab_widget__container{position:relative;background-color:#fff;border-radius:6px;display:flex;align-items:center;width:340px;height:104px;transition:transform 0.5s linear}.tab_widget__container-visible{transform:translate(0)}.tab_widget__arc-container{margin-right:6px;width:calc(64px + 6px);height:64px;position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:center}.tab_widget__arc--background{position:absolute;stroke:#cbd5e0}.tab_widget__arc--filled{position:absolute;stroke:#000;stroke-dasharray:175.84;stroke-dashoffset:175.84}.tab_widget__arc-animation{-webkit-animation:animateTabAmount 0.5s linear forwards;animation:animateTabAmount 0.5s linear forwards}.tab_widget__arc-animation--pulse{stroke:#000;animation:pulse 1s ease-in-out alternate-reverse infinite}.tab_widget__arc-animation--pulse circle{stroke:#000;stroke-opacity:inherit}@-webkit-keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@-webkit-keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}@keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}.tab_widget__donated-amount-text{font-weight:700}.tab_widget__thank-you-message{font-weight:500;margin:0;margin-bottom:5px;font-size:19px;color:#1d1d1d;text-align:left}.tab_widget__regular-text{font-weight:400;font-size:15px;margin:0;margin-bottom:5px;color:#333}.tab_widget__links-container{display:flex;align-items:center}a.tab_widget__link{font-weight:400;margin:0;font-size:13px;color:#1d1d1d;text-decoration:underline;cursor:pointer}a.tab_widget__link:hover,a.tab_widget__link:visited{color:#1d1d1d}.tab_widget__links-separator{padding-right:5px;padding-left:5px;color:#333}.tab_widget__container-hidden{transform:translate(500px)}.tab__widget__info-button__container{position:absolute;right:6px;top:6px;cursor:pointer}.tab__widget__info-button{position:relative}.tab__widget__info-button-question-mark{position:absolute;font-weight:700;font-size:12px;color:#fff;left:34%;top:0}.tab__widget__close-button-x-mark{left:33%;top:-1px}.tab_widget__container__info-screen{position:absolute;height:100%;width:calc(100% + 50px);margin-top:-35px;margin-left:-25px;z-index:10;visibility:var(--infoScreenVisibility);text-align:left}.tab_widget__info_container{position:relative;padding:20px;background-color:#fff;box-shadow:0 1px 8px 0 rgba(29,29,29,0.16);border-radius:6px}.tab_widget__info-title{font-weight:500;font-size:18px;margin:0}.tab_widget__info-steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.tab_widget__info-step{display:flex;align-items:center;font-weight:500;font-size:14px;margin:0}.tab_widget__info-step-text{margin-left:6px;margin-right:10px}.tab_widget__info-step-number{display:flex;justify-content:center;align-items:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.tab_widget__info-description{font-weight:500;font-size:14px}.tab_widget__info-description p{margin-bottom:1em}.tab_widget__info-description p:last-child{margin-bottom:0}.tab__widget__icon{position:unset;height:18px;width:18px}
    22
  • revenue-generator/tags/2.0.1/v2/assets/build/frontend.js

    r2466307 r2468562  
    1 (()=>{"use strict";(()=>{const t=t=>{const e=t+"=",o=decodeURIComponent(document.cookie).split(";");for(let t=0;t<o.length;t++){let s=o[t];for(;" "===s.charAt(0);)s=s.substring(1);if(0===s.indexOf(e))return s.substring(e.length,s.length)}return""};class e{constructor(t){this.el=t,this.itemId=this.el.dataset.contributionId,this.closeTimeout=null,this.RESET_TIMEOUT=3e3,this.$o={form:t.querySelector(".rev-gen-contribution__form"),submitButton:t.querySelector("button[type=submit][data-mytab-button]"),amounts:t.querySelector(".rev-gen-contribution__amounts"),choose:t.querySelector(".rev-gen-contribution__choose"),customChoice:t.querySelector(".rev-gen-contribution__amount--custom"),response:t.querySelector(".rev-gen-contribution__response"),loading:t.querySelector(".rev-gen-contribution__loading"),custom:{el:t.querySelector(".rev-gen-contribution__custom"),input:t.querySelector(".rev-gen-contribution__custom input"),backButton:t.querySelector(".rev-gen-contribution-custom__back")},modal:{el:t.querySelector(".rev-gen-contribution-info-modal"),openButton:t.querySelector(".rev-gen-contribution__question-mark"),closeButton:t.querySelector(".rev-gen-contribution-info-modal__x-mark")}},this.bindEvents(),this.maybeContinueFlow()}bindEvents(){const t=this;new ResizeObserver((t=>{t.forEach((t=>{const e=t.target.dataset.breakpoints?JSON.parse(t.target.dataset.breakpoints):"";e&&Object.keys(e).forEach((o=>{const s=e[o],n="size-"+o;t.contentRect.width>=s?t.target.classList.add(n):t.target.classList.remove(n)}))}))})).observe(this.el),this.$o.customChoice.addEventListener("click",(t=>{t.preventDefault(),this.showCustomForm()})),this.$o.custom.backButton.addEventListener("click",(t=>{t.preventDefault(),this.hideCustomForm()})),this.$o.form.addEventListener("change",(()=>{this.customModeActive||(new FormData(this.$o.form).get("amount")?(this.el.classList.add("amount-selected"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.submitButton.removeAttribute("hidden")):(this.el.classList.remove("amount-selected"),this.$o.submitButton.classList.add("rev-gen-hidden"),this.$o.submitButton.addAttribute("hidden")))})),this.$o.form.addEventListener("submit",(e=>{e.preventDefault();const o=new FormData(this.$o.form),s=new XMLHttpRequest;s.open("POST",this.$o.form.getAttribute("action"),!0),s.send(o),s.onreadystatechange=function(){if(4===this.readyState){const e=JSON.parse(this.response);switch(this.status){case 200:const o=document.createElement("script");o.src=t.$o.form.dataset.tabWidgetUrl,t.$o.response.appendChild(o),t.$o.response.innerHTML=e.data.html,o.onload=()=>{t.$o.choose.classList.add("rev-gen-hidden");const e=t.el.querySelectorAll(".tab_widget__link")[1];t.setCloseTimeout(),e.addEventListener("click",(()=>{t.openInfoModal()})),t.hideSubmit()};break;case 402:t.$o.modal.openButton.classList.add("rev-gen-hidden"),t.$o.loading.classList.remove("rev-gen-hidden"),t.el.classList.add("rev-gen-contribution--payment"),t.$o.response.innerHTML=e.data.html,t.$o.choose.classList.add("rev-gen-hidden"),t.hideSubmit();break;case 401:window.location.href=e.data.auth_url}}}})),this.$o.modal.openButton.addEventListener("click",(()=>{t.openInfoModal()})),this.$o.modal.closeButton.addEventListener("click",(()=>{t.closeInfoModal()})),window.addEventListener("message",(e=>{e.data&&"OPEN_INFO_MODAL"===e.data&&t.openInfoModal()})),window.addEventListener("message",(e=>{e.data&&"PAYMENT_SUCCESSFUL"===e.data&&t.reset()})),this.el.addEventListener("rev-gen-iframe-load",(e=>{const o=e.detail||"";o&&(t.$o.loading.classList.add("rev-gen-hidden"),t.$o.modal.openButton.classList.remove("rev-gen-hidden"),o.style.height=o.contentWindow.document.body.scrollHeight+"px",t.el.classList.add("rev-gen-iframe-ready"))}))}hideSubmit(){this.$o.submitButton.classList.add("rev-gen-hidden")}showCustomForm(){this.customModeActive=!0,this.$o.amounts.classList.add("rev-gen-hidden"),this.$o.custom.el.classList.remove("rev-gen-hidden"),this.$o.custom.el.removeAttribute("hidden"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.custom.input.focus()}hideCustomForm(){this.customModeActive=!1,this.$o.form.reset(),this.$o.custom.el.classList.add("rev-gen-hidden"),this.$o.custom.el.setAttribute("hidden",""),this.$o.amounts.classList.remove("rev-gen-hidden"),this.$o.submitButton.classList.add("rev-gen-hidden")}openInfoModal(){clearTimeout(this.closeTimeout),this.$o.modal.el.classList.remove("rev-gen-hidden")}closeInfoModal(){this.$o.modal.el.classList.add("rev-gen-hidden")}reset(){this.el.classList.remove("amount-selected"),this.$o.response.innerHTML="",this.el.classList.remove("rev-gen-contribution--payment"),this.$o.form.reset(),this.$o.choose.classList.remove("rev-gen-hidden")}setCloseTimeout(){const t=this;this.closeTimeout=setTimeout((()=>{t.reset()}),t.RESET_TIMEOUT)}maybeContinueFlow(){if(!t("rgv2_data"))return;const e=JSON.parse(t("rgv2_data"));if(parseInt(this.itemId,10)!==parseInt(e.contribution.item_id,10))return;const o=this.$o.form.querySelector('[value="'+e.contribution.amount+'"]');o?o.checked=!0:(this.$o.custom.input.value=o,this.showCustomForm());const s=new MouseEvent("click");this.$o.submitButton.dispatchEvent(s)}}window.laterpayIframeLoaded=t=>{const e=t.dataset.contributionId;if(!e)return;const o=new CustomEvent("rev-gen-iframe-load",{detail:t});let s=document.querySelectorAll('.rev-gen-contribution[data-contribution-id="'+e+'"]');s=s[s.length-1],s.dispatchEvent(o)};class o{constructor(t){this.$button={trigger:t.querySelector("button"),modal:t.querySelector(".rev-gen-contribution-modal")},this.$modal={el:""},this.bindButtonEvents()}bindButtonEvents(){this.$button.trigger.addEventListener("click",this.open.bind(this))}bindModalEvents(){this.$modal.closeButton.addEventListener("click",this.close.bind(this))}open(t){t.preventDefault();const e=this.$button.modal.cloneNode(!0);this.$modal.el=e,this.$modal.contributionEl=e.querySelector(".rev-gen-contribution"),this.$modal.closeButton=e.querySelector(".rev-gen-contribution-modal__close"),document.querySelector("body").appendChild(e),this.bindModalEvents(),this.initContributionRequest(),setTimeout((function(){e.classList.add("active")}),100)}initContributionRequest(){this.contributionInstance=new e(this.$modal.contributionEl)}close(t){t.preventDefault();const e=this.$modal.el;e.classList.remove("active"),setTimeout((function(){document.querySelector("body").removeChild(e)}),200)}}document.addEventListener("DOMContentLoaded",(()=>{const t=document.getElementsByClassName("rev-gen-contribution");for(const s of t)s.dataset.type&&("button"!==s.dataset.type?new e(s):new o(s))}))})()})();
     1(()=>{"use strict";(()=>{const t=t=>{const e=t+"=",o=decodeURIComponent(document.cookie).split(";");for(let t=0;t<o.length;t++){let n=o[t];for(;" "===n.charAt(0);)n=n.substring(1);if(0===n.indexOf(e))return n.substring(e.length,n.length)}return""},e=(t,e,o)=>{const n=new Date;n.setTime(n.getTime()+24*o*60*60*1e3);const s="expires="+n.toUTCString();document.cookie=t+"="+e+";"+s+";path=/"};class o{constructor(t){this.el=t,this.itemId=this.el.dataset.contributionId,this.closeTimeout=null,this.RESET_TIMEOUT=3e3,this.$o={form:t.querySelector(".rev-gen-contribution__form"),submitButton:t.querySelector("button[type=submit][data-mytab-button]"),amounts:t.querySelector(".rev-gen-contribution__amounts"),choose:t.querySelector(".rev-gen-contribution__choose"),customChoice:t.querySelector(".rev-gen-contribution__amount--custom"),response:t.querySelector(".rev-gen-contribution__response"),loading:t.querySelector(".rev-gen-contribution__loading"),custom:{el:t.querySelector(".rev-gen-contribution__custom"),input:t.querySelector(".rev-gen-contribution__custom input"),backButton:t.querySelector(".rev-gen-contribution-custom__back")},modal:{el:t.querySelector(".rev-gen-contribution-info-modal"),openButton:t.querySelector(".rev-gen-contribution__question-mark"),closeButton:t.querySelector(".rev-gen-contribution-info-modal__x-mark")}},this.bindEvents(),this.maybeContinueFlow()}bindEvents(){const o=this;new ResizeObserver((t=>{t.forEach((t=>{const e=t.target.dataset.breakpoints?JSON.parse(t.target.dataset.breakpoints):"";e&&Object.keys(e).forEach((o=>{const n=e[o],s="size-"+o;t.contentRect.width>=n?t.target.classList.add(s):t.target.classList.remove(s)}))}))})).observe(this.el),this.$o.customChoice.addEventListener("click",(t=>{t.preventDefault(),this.showCustomForm()})),this.$o.custom.backButton.addEventListener("click",(t=>{t.preventDefault(),this.hideCustomForm()})),this.$o.form.addEventListener("change",(()=>{this.customModeActive||(new FormData(this.$o.form).get("amount")?(this.el.classList.add("amount-selected"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.submitButton.removeAttribute("hidden")):(this.el.classList.remove("amount-selected"),this.$o.submitButton.classList.add("rev-gen-hidden"),this.$o.submitButton.addAttribute("hidden")))})),this.$o.form.addEventListener("submit",(n=>{n.preventDefault();const s=new FormData(this.$o.form);s.append("rg_key",t("rg_key"));const i=new XMLHttpRequest;i.open("POST",this.$o.form.getAttribute("action"),!0),i.send(s),i.onreadystatechange=function(){if(4===this.readyState){const t=JSON.parse(this.response);switch(this.status){case 200:const n=document.createElement("script");n.src=o.$o.form.dataset.tabWidgetUrl,o.$o.response.appendChild(n),o.$o.response.innerHTML=t.data.html,n.onload=()=>{o.$o.choose.classList.add("rev-gen-hidden");const t=o.el.querySelectorAll(".tab_widget__link")[1];o.setCloseTimeout(),t.addEventListener("click",(()=>{o.openInfoModal()})),o.hideSubmit()};break;case 402:o.$o.modal.openButton.classList.add("rev-gen-hidden"),o.$o.loading.classList.remove("rev-gen-hidden"),o.el.classList.add("rev-gen-contribution--payment"),o.$o.response.innerHTML=t.data.html,o.$o.choose.classList.add("rev-gen-hidden"),o.hideSubmit();break;case 401:e("rg_key",t.data.session_key),e("rg_contribution_data",JSON.stringify(t.data.handover)),window.location.href=t.data.auth_url}}}})),this.$o.modal.openButton.addEventListener("click",(()=>{o.openInfoModal()})),this.$o.modal.closeButton.addEventListener("click",(()=>{o.closeInfoModal()})),window.addEventListener("message",(t=>{t.data&&"OPEN_INFO_MODAL"===t.data&&o.openInfoModal()})),window.addEventListener("message",(t=>{t.data&&"PAYMENT_SUCCESSFUL"===t.data&&o.reset()})),this.el.addEventListener("rev-gen-iframe-load",(t=>{const e=t.detail||"";e&&(o.$o.loading.classList.add("rev-gen-hidden"),o.$o.modal.openButton.classList.remove("rev-gen-hidden"),e.style.height=e.contentWindow.document.body.scrollHeight+"px",o.el.classList.add("rev-gen-iframe-ready"))}))}hideSubmit(){this.$o.submitButton.classList.add("rev-gen-hidden")}showCustomForm(){this.customModeActive=!0,this.$o.amounts.classList.add("rev-gen-hidden"),this.$o.custom.el.classList.remove("rev-gen-hidden"),this.$o.custom.el.removeAttribute("hidden"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.custom.input.focus()}hideCustomForm(){this.customModeActive=!1,this.$o.form.reset(),this.$o.custom.el.classList.add("rev-gen-hidden"),this.$o.custom.el.setAttribute("hidden",""),this.$o.amounts.classList.remove("rev-gen-hidden"),this.$o.submitButton.classList.add("rev-gen-hidden")}openInfoModal(){clearTimeout(this.closeTimeout),this.$o.modal.el.classList.remove("rev-gen-hidden")}closeInfoModal(){this.$o.modal.el.classList.add("rev-gen-hidden")}reset(){this.el.classList.remove("amount-selected"),this.$o.response.innerHTML="",this.el.classList.remove("rev-gen-contribution--payment"),this.$o.form.reset(),this.$o.choose.classList.remove("rev-gen-hidden")}setCloseTimeout(){const t=this;this.closeTimeout=setTimeout((()=>{t.reset()}),t.RESET_TIMEOUT)}maybeContinueFlow(){if(!t("rg_contribution_data"))return;const o=JSON.parse(t("rg_contribution_data"));if(parseInt(this.itemId,10)!==parseInt(o.contribution.item_id,10))return;const n=this.$o.form.querySelector('[value="'+o.contribution.amount+'"]');n?n.checked=!0:(this.$o.custom.input.value=n,this.showCustomForm());const s=new MouseEvent("click");this.$o.submitButton.dispatchEvent(s),e("rg_contribution_data","")}}window.laterpayIframeLoaded=t=>{const e=t.dataset.contributionId;if(!e)return;const o=new CustomEvent("rev-gen-iframe-load",{detail:t});let n=document.querySelectorAll('.rev-gen-contribution[data-contribution-id="'+e+'"]');n=n[n.length-1],n.dispatchEvent(o)};class n{constructor(t){this.$button={trigger:t.querySelector("button"),modal:t.querySelector(".rev-gen-contribution-modal")},this.$modal={el:""},this.bindButtonEvents()}bindButtonEvents(){this.$button.trigger.addEventListener("click",this.open.bind(this))}bindModalEvents(){this.$modal.closeButton.addEventListener("click",this.close.bind(this))}open(t){t.preventDefault();const e=this.$button.modal.cloneNode(!0);this.$modal.el=e,this.$modal.contributionEl=e.querySelector(".rev-gen-contribution"),this.$modal.closeButton=e.querySelector(".rev-gen-contribution-modal__close"),document.querySelector("body").appendChild(e),this.bindModalEvents(),this.initContributionRequest(),setTimeout((function(){e.classList.add("active")}),100)}initContributionRequest(){this.contributionInstance=new o(this.$modal.contributionEl)}close(t){t.preventDefault();const e=this.$modal.el;e.classList.remove("active"),setTimeout((function(){document.querySelector("body").removeChild(e)}),200)}}document.addEventListener("DOMContentLoaded",(()=>{const t=document.getElementsByClassName("rev-gen-contribution");for(const e of t)e.dataset.type&&("button"!==e.dataset.type?new o(e):new n(e))}))})()})();
  • revenue-generator/tags/2.0.1/v2/assets/src/js/frontend/contribution.js

    r2466307 r2468562  
    11/* global FormData, XMLHttpRequest, ResizeObserver, MouseEvent, CustomEvent */
    22
    3 import { getCookie } from '../helpers/index';
     3import { setCookie, getCookie } from '../helpers/index';
    44
    55/**
     
    134134            // Get form data.
    135135            const data = new FormData( this.$o.form );
     136            data.append( 'rg_key', getCookie( 'rg_key' ) );
    136137
    137138            // Create ajax object.
     
    145146                    const res = JSON.parse( this.response );
    146147
    147                     /* eslint-disable no-alert */
    148148                    switch ( this.status ) {
    149149                        // Item added to the tab.
     
    195195                        // User not authorized.
    196196                        case 401:
     197                            setCookie( 'rg_key', res.data.session_key );
     198                            setCookie(
     199                                'rg_contribution_data',
     200                                JSON.stringify( res.data.handover )
     201                            );
     202
    197203                            // Redirect to auth.
    198204                            window.location.href = res.data.auth_url;
    199205                            break;
    200206                    }
    201                     /* eslint-enable no-alert */
    202207                }
    203208            };
     
    326331     */
    327332    maybeContinueFlow() {
    328         if ( ! getCookie( 'rgv2_data' ) ) {
     333        if ( ! getCookie( 'rg_contribution_data' ) ) {
    329334            return;
    330335        }
    331336
    332         const clientCookie = JSON.parse( getCookie( 'rgv2_data' ) );
     337        const clientCookie = JSON.parse( getCookie( 'rg_contribution_data' ) );
    333338
    334339        if (
     
    358363        const clickEvent = new MouseEvent( 'click' );
    359364        this.$o.submitButton.dispatchEvent( clickEvent );
     365
     366        // Reset session cookie to empty value after making a contribution.
     367        setCookie( 'rg_contribution_data', '' );
    360368    }
    361369}
  • revenue-generator/tags/2.0.1/v2/assets/src/js/helpers/index.js

    r2466307 r2468562  
    2525    return '';
    2626};
     27
     28export const setCookie = ( cname, cvalue, expDays ) => {
     29    const d = new Date();
     30    d.setTime( d.getTime() + expDays * 24 * 60 * 60 * 1000 );
     31    const expires = 'expires=' + d.toUTCString();
     32    document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
     33};
  • revenue-generator/tags/2.0.1/v2/assets/src/scss/frontend/_component.scss

    r2466307 r2468562  
    116116}
    117117
    118 .tab_widget__link {
     118a.tab_widget__link {
    119119    @extend .font;
    120120    font-weight: 400;
     
    124124    text-decoration: underline;
    125125    cursor: pointer;
     126    &:hover,
     127    &:visited {
     128        color: $color-dark;
     129    }
    126130}
    127131
  • revenue-generator/tags/2.0.1/v2/assets/src/scss/frontend/contribution-dialog.scss

    r2466307 r2468562  
    4545        height: 18px;
    4646        border-radius: 50%;
     47        font-family: $box-font;
    4748        font-weight: 700;
    4849        font-size: 12px;
     
    8182        &__title {
    8283            margin: 0;
     84            font-family: $box-font;
    8385            font-weight: 500;
    8486            font-size: 18px;
     
    9496            align-items: center;
    9597            margin: 0;
     98            font-family: $box-font;
    9699            font-weight: 500;
    97100            font-size: 14px;
     
    113116        }
    114117        &__description {
    115             font-weight: 500;
    116             font-size: 14px;
    117 
    118118            p {
    119119                margin-bottom: 1em;
     120                font-family: $box-font;
     121                font-weight: 500;
     122                font-size: 14px;
    120123                &:last-child {
    121124                    margin-bottom: 0;
     
    164167        &.amp-form-submit-success,
    165168        &.amp-form-submit-error {
     169            max-height: 250px;
     170            overflow: hidden;
    166171            margin: 0;
    167172        }
     173        div[submit-success] {
     174            position: relative;
     175            z-index: 10;
     176        }
    168177        button[type="submit"] {
     178            cursor: pointer;
    169179            max-width: 100%;
    170180            flex: 0 1 100%;
    171181            width: 100%;
    172182            padding: 15px 0;
     183            font-family: $box-font;
    173184            font-size: 15px;
    174185            border: 1px solid #000;
     
    274285        input[type="number"] {
    275286            min-width: 220px;
    276             margin-right: 5px;
     287            margin: 0 5px 0 0;
    277288            padding: 13.5px 0 13px 15px;
    278289            border-radius: 5px;
    279290            background-color: rgba(160, 160, 160, 0.12);
    280             margin-bottom: 10px;
     291            font-family: $box-font;
    281292            font-size: 14px;
    282293            outline: 0;
     
    351362        &__back {
    352363            position: relative;
    353             bottom: 5px;
     364            bottom: 0;
    354365            float: left;
    355366            cursor: pointer;
     
    640651    &__amp-show-modal {
    641652        position: absolute;
    642         bottom: 35px;
    643         left: 165px;
     653        bottom: 19px;
     654        left: 137px;
    644655        z-index: 10;
    645656        width: 95px;
  • revenue-generator/tags/2.0.1/v2/inc/classes/api/class-auth-provider.php

    r2466307 r2468562  
    7474
    7575    /**
     76     * Returns a new random string to use as the state parameter in an
     77     * authorization flow.
     78     *
     79     * Adds support for PHP5 by generating state with `openssl_random_pseudo_bytes` if
     80     * `random_bytes` does not exist.
     81     *
     82     * @param  int $length Length of the random string to be generated.
     83     * @return string
     84     */
     85    protected function getRandomState( $length = 32 ) {
     86        if ( function_exists( 'random_bytes' ) ) {
     87            return bin2hex( random_bytes( $length / 2 ) );
     88        }
     89
     90        if ( function_exists( 'openssl_random_pseudo_bytes' ) ) {
     91            return bin2hex( openssl_random_pseudo_bytes( $length / 2 ) );
     92        }
     93    }
     94
     95    /**
    7696     * Check response and throw exception if error is present.
    7797     *
  • revenue-generator/tags/2.0.1/v2/inc/classes/api/class-auth.php

    r2466307 r2468562  
    3838     */
    3939    const SERVER_KEY_OPTION_NAME = 'lp_rgv2_key';
    40 
    41     /**
    42      * Name of the cookie to store JWT.
    43      *
    44      * @const string
    45      */
    46     const TOKEN_COOKIE_NAME = 'rgv2_token';
    4740
    4841    /**
     
    151144
    152145    /**
    153      * Get tokens from client.
    154      *
    155      * @return boolean|JSON False on failure, JSON object on success.
    156      */
    157     private function get_jwt_from_client() {
    158         $jwt = ( isset( $_COOKIE[ self::TOKEN_COOKIE_NAME ] ) ) ? sanitize_text_field( $_COOKIE[ self::TOKEN_COOKIE_NAME ] ) : '';
    159 
    160         if ( empty( $jwt ) ) {
    161             return false;
    162         }
    163 
    164         $tokens = $this->decode_tokens( $jwt );
     146     * Get token from database if key is set.
     147     *
     148     * @return JWT
     149     */
     150    public function get_token_from_db() {
     151        $api = API::get_instance();
     152
     153        // Return false if session key is not set.
     154        if ( empty( $api->session_key ) ) {
     155            return false;
     156        }
     157
     158        // Get token by session key.
     159        $tokens = get_transient( wp_hash( $api->session_key ) );
     160        $tokens = $this->decode_tokens( $tokens, $api->session_key );
    165161
    166162        if ( is_wp_error( $tokens ) ) {
     
    174170     * Get access token.
    175171     *
    176      * This looks for a token on client first, returns false if it's not found so we can then
     172     * This looks for a token in database first, returns false if it's not found so we can then
    177173     * start the authorization code flow.
    178174     *
     
    186182        }
    187183
    188         // Get tokens from the client.
    189         $tokens = $this->get_jwt_from_client();
     184        // Get tokens from the database.
     185        $tokens = $this->get_token_from_db();
    190186
    191187        if ( ! $tokens ) {
     
    216212        }
    217213
     214        if ( ! isset( $_GET['state'] ) ) {
     215            return;
     216        }
     217
     218        $state = sanitize_text_field( $_GET['state'] );
     219
     220        $api = API::get_instance();
     221        $api->set_session( $state );
     222
    218223        $tokens = $this->get_tokens_from_provider(
    219224            'authorization_code',
    220             sanitize_text_field( $_GET['code'] )
    221         );
     225            sanitize_text_field( $_GET['code'] ),
     226            $state
     227        );
     228
     229        $client_data = $api->get_client_meta();
     230
     231        // If this is AMP, pair token to AMP client ID instead.
     232        if ( isset( $client_data['amp_id_key'] ) ) {
     233            delete_transient( wp_hash( $state ) );
     234
     235            $this->save_tokens( $tokens, $client_data['amp_id_key'] );
     236        }
    222237
    223238        $redirect_uri = site_url();
    224         $client_data  = API::get_user_cookie();
    225 
    226         if ( isset( $client_data->redirect_uri ) && ! empty( $client_data->redirect_uri ) ) {
    227             $redirect_uri = $client_data->redirect_uri;
    228         }
     239
     240        if ( isset( $client_data['redirect_uri'] ) && ! empty( $client_data['redirect_uri'] ) ) {
     241            $redirect_uri = $client_data['redirect_uri'];
     242        }
     243
     244        $api->delete_client_meta();
    229245
    230246        wp_safe_redirect( $redirect_uri );
     
    237253     * @param string $grant_type Grant type to use when obtaining a token.
    238254     * @param string $key        A key to use with the flow (auth code or refresh token).
     255     * @param string $state      OAuth state.
    239256     *
    240257     * @return AccessToken|boolean Token class instance. Boolean on failure.
    241258     */
    242     public function get_tokens_from_provider( $grant_type = 'refresh_token', $key = '' ) {
     259    public function get_tokens_from_provider( $grant_type = 'refresh_token', $key = '', $state = '' ) {
    243260        if ( empty( $key ) ) {
    244261            return false;
     
    267284            $tokens = $this->provider->getAccessToken( $grant_type, $params );
    268285
    269             $this->save_tokens( $tokens );
     286            $this->save_tokens( $tokens, $state );
    270287
    271288            return $tokens;
     
    281298     *
    282299     * @param AccessToken $tokens AccessToken instance.
     300     * @param string      $state  OAuth state.
    283301     *
    284302     * @return string Access token.
    285303     */
    286     public function save_tokens( AccessToken $tokens ) {
     304    public function save_tokens( AccessToken $tokens, $state ) {
    287305        $this->token    = $tokens->getToken();
    288         $encoded_tokens = $this->encode_tokens( $tokens );
    289 
    290         if ( isset( $_COOKIE[ self::TOKEN_COOKIE_NAME ] ) ) {
    291             unset( $_COOKIE[ self::TOKEN_COOKIE_NAME ] );
    292         }
    293 
    294         if ( ! headers_sent() ) {
    295             setcookie(
    296                 self::TOKEN_COOKIE_NAME,
    297                 $encoded_tokens,
    298                 [
    299                     'path'     => '/',
    300                     'httponly' => true,
    301                     'secure'   => is_ssl(),
    302                     'samesite' => true,
    303                     'expires'  => time() + 720 * HOUR_IN_SECONDS,
    304                 ]
    305             );
    306         }
     306        $encoded_tokens = $this->encode_tokens( $tokens, $state );
     307
     308        delete_transient( wp_hash( $state ) );
     309        set_transient( wp_hash( $state ), $encoded_tokens, 1 * MONTH_IN_SECONDS );
    307310
    308311        return $this->token;
     
    313316     *
    314317     * @param AccessToken $tokens AccessToken instance.
    315      *
    316      * @return string JWT token.
    317      */
    318     private function encode_tokens( AccessToken $tokens ) {
     318     * @param string      $key    Key to encode tokens with.
     319     *
     320     * @return mixed JWT token on success, FALSE on failure.
     321     */
     322    private function encode_tokens( AccessToken $tokens, $key = '' ) {
     323        if ( empty( $key ) ) {
     324            return false;
     325        }
     326
    319327        $payload = [
    320328            'access'  => $tokens->getToken(),
     
    323331        ];
    324332
    325         $jwt = JWT::encode( $payload, $this->key );
     333        $jwt = JWT::encode( $payload, $key );
    326334
    327335        return $jwt;
     
    332340     *
    333341     * @param string $jwt String to decode.
     342     * @param string $key Key to decode token with.
    334343     *
    335344     * @return JSON|WP_Error JSON object on success. WP_Error object on failure.
    336345     */
    337     private function decode_tokens( $jwt = '' ) {
     346    private function decode_tokens( $jwt = '', $key = '' ) {
    338347        if ( empty( $jwt ) ) {
    339348            return new \WP_Error( 'empty_jwt', 'JWT parameter cannot be empty to decode it.' );
    340349        }
    341350
     351        if ( empty( $key ) ) {
     352            return new \WP_Error( 'empty_key', 'Key needs to be provided to decode JWT token.' );
     353        }
     354
    342355        try {
    343             $decoded = JWT::decode( $jwt, $this->key, [ 'HS256' ] );
     356            $decoded = JWT::decode( $jwt, $key, [ 'HS256' ] );
    344357
    345358            return $decoded;
     
    551564     */
    552565    public function get_auth_code_url() {
    553         return $this->provider->getAuthorizationUrl();
     566        $url = $this->provider->getAuthorizationUrl();
     567
     568        return $url;
     569    }
     570
     571    /**
     572     * Get state from the authorization code flow URL.
     573     *
     574     * @param string $url URL to get the state from.
     575     *
     576     * @return string
     577     */
     578    public function get_state_from_auth_url( $url = '' ) {
     579        if ( empty( $url ) ) {
     580            return '';
     581        }
     582
     583        $parsed_url = parse_url( $url );
     584        parse_str( $parsed_url['query'], $query_params );
     585
     586        if ( ! isset( $query_params['state'] ) ) {
     587            return '';
     588        }
     589
     590        return sanitize_text_field( $query_params['state'] );
    554591    }
    555592
  • revenue-generator/tags/2.0.1/v2/inc/classes/class-api.php

    r2466307 r2468562  
    3434
    3535    /**
    36      * Name of the cookie to store temporary data on client.
    37      *
    38      * @const string
    39      */
    40     const CLIENT_COOKIE_NAME = 'rgv2_data';
    41 
    42     /**
    43      * Name of the cookie with full tab ID info.
    44      *
    45      * @const string
    46      */
    47     const FULL_TAB_COOKIE_NAME = 'rgv2_full_tab_id';
    48 
    49     /**
    5036     * Auth instance.
    5137     *
     
    5339     */
    5440    public static $auth = null;
     41
     42    /**
     43     * Session key to manage meta.
     44     *
     45     * @var string
     46     */
     47    public $session_key = '';
     48
     49    /**
     50     * Hashed session key.
     51     *
     52     * @var string
     53     */
     54    private $hashed_key = '';
    5555
    5656    /**
     
    239239
    240240    /**
    241      * Get value of user cookie used when user needs to leave the site
    242      * to go through the auth process. Used to store redirect URI and amount
    243      * to contribute here.
    244      *
    245      * @return mixed Empty array on failure. JSON object on success.
    246      */
    247     public static function get_user_cookie() {
    248         $data = [];
    249 
    250         if ( ! isset( $_COOKIE[ static::CLIENT_COOKIE_NAME ] ) ) {
    251             return $data;
    252         }
    253 
    254         $data = $_COOKIE[ static::CLIENT_COOKIE_NAME ]; // phpcs:ignore -- WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    255         $data = json_decode( stripslashes( $data ) );
    256 
    257         return $data;
    258     }
    259 
    260     /**
    261      * Return user cookie parameters.
    262      *
    263      * @return array
    264      */
    265     private static function get_user_cookie_params() {
    266         return [
    267             'path'     => '/',
    268             'secure'   => is_ssl(),
    269         ];
    270     }
    271 
    272     /**
    273      * Sets data to user cookie. Unsets the cookie first if it was previously set.
    274      *
    275      * @param array $data Data to be set.
     241     * Set session key.
     242     *
     243     * @param string $session_key Session key to set.
     244     */
     245    public function set_session( $session_key = '' ) {
     246        $this->session_key = $session_key;
     247        $this->hashed_key  = wp_hash( $this->session_key );
     248    }
     249
     250    /**
     251     * Set client meta in database.
     252     *
     253     * @param string $data       Data to be stored.
     254     * @param string $type       Type of meta. Default: `meta`.
     255     * @param int    $expiration The expiration after which data will be deleted.
    276256     *
    277257     * @return void
    278258     */
    279     public static function set_user_cookie( $data = [] ) {
    280         static::unset_user_cookie();
    281 
    282         setcookie(
    283             static::CLIENT_COOKIE_NAME,
    284             json_encode( $data ),
    285             static::get_user_cookie_params()
    286         );
    287     }
    288 
    289     /**
    290      * Unsets user cookie.
    291      */
    292     public static function unset_user_cookie() {
    293         setcookie(
    294             static::CLIENT_COOKIE_NAME,
    295             '',
    296             static::get_user_cookie_params()
    297         );
    298     }
    299 
    300     /**
    301      * Sets cookie with full tab ID.
    302      *
    303      * @param string $value Tab ID.
     259    public function set_client_meta( $data = '', $type = 'meta', $expiration = 5 * MINUTE_IN_SECONDS ) {
     260        $transient_key = "{$this->hashed_key}_{$type}";
     261
     262        set_transient( $transient_key, $data, $expiration );
     263    }
     264
     265    /**
     266     * Get client meta from the database.
     267     *
     268     * @param string $type Type of meta. Default: `meta`.
     269     *
     270     * @return mixed
     271     */
     272    public function get_client_meta( $type = 'meta' ) {
     273        $transient_key = "{$this->hashed_key}_{$type}";
     274
     275        return get_transient( $transient_key );
     276    }
     277
     278    /**
     279     * Delete client meta from the database.
     280     *
     281     * @param string $type Type of meta to be deleted. Default: `meta`.
    304282     *
    305283     * @return void
    306284     */
    307     public static function set_full_tab_cookie( $value = '' ) {
    308         $params             = static::get_user_cookie_params();
    309         $params['httponly'] = true;
    310 
    311         setcookie(
    312             static::FULL_TAB_COOKIE_NAME,
    313             $value,
    314             $params
    315         );
    316     }
    317 
    318     /**
    319      * Get value of full tab cookie.
    320      *
    321      * @return string
    322      */
    323     public static function get_full_tab_cookie() {
    324         $value = '';
    325 
    326         if ( ! isset( $_COOKIE[ static::FULL_TAB_COOKIE_NAME ] ) ) {
    327             return $value;
    328         }
    329 
    330         $value = sanitize_text_field( $_COOKIE[ static::FULL_TAB_COOKIE_NAME ] );
    331 
    332         return $value;
    333     }
    334 
    335     /**
    336      * Unsets cookie with full tab ID.
    337      */
    338     public static function unset_full_tab_cookie() {
    339         static::set_full_tab_cookie( '' );
     285    public function delete_client_meta( $type = 'meta' ) {
     286        $transient_key = "{$this->hashed_key}_{$type}";
     287
     288        delete_transient( $transient_key );
    340289    }
    341290
  • revenue-generator/tags/2.0.1/v2/inc/classes/class-frontend-post.php

    r2466307 r2468562  
    3636     * @const string
    3737     */
    38     const TAB_WIDGET_SCRIPT_URL = 'https://assets.sbx.laterpay.net/pcpro-jsx-components-frontend/main.js';
     38    const TAB_WIDGET_SCRIPT_URL = 'https://assets.laterpay.net/pcpro-jsx-components-frontend/main.js';
    3939
    4040    /**
     
    7272     */
    7373    const MYTAB_SBX_URL = 'https://mytab.sbx.laterpay.net';
    74 
    75     /**
    76      * Tab data cookie name for AMP context.
    77      *
    78      * @const string
    79      */
    80     const AMP_TAB_DATA_COOKIE_NAME = 'amp_lp_tab_data';
    8174
    8275    /**
     
    131124        add_action( 'parse_request', [ $this, 'handle_payment_iframe_redirect' ] );
    132125        add_action( 'parse_request', [ $this, 'handle_purchase_iframe_display' ] );
     126        add_action( 'parse_request', [ $this, 'handle_json_amp_url' ] );
     127        add_action( 'wp_print_footer_scripts', [ $this, 'print_amp_script' ] );
     128        add_action( 'wp_head', [ $this, 'add_amp_script_hash' ] );
    133129    }
    134130
     
    187183        $is_amp        = ( isset( $_REQUEST['is_amp'] ) && 1 === (int) $_REQUEST['is_amp'] );
    188184        $layout_type   = ( isset( $_REQUEST['layout_type'] ) ) ? sanitize_text_field( $_REQUEST['layout_type'] ) : '';
     185        $key           = ( isset( $_REQUEST['rg_key'] ) ) ? sanitize_text_field( $_REQUEST['rg_key'] ) : '';
    189186        $redirect_uri  = ( isset( $_REQUEST['redirect_uri'] ) ) ? esc_url( $_REQUEST['redirect_uri'] ) : ''; // phpcs:ignore -- WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    190187
     
    210207        $api = API::get_instance();
    211208
     209        // If session key is present, set it to API instance.
     210        if ( ! empty( $key ) ) {
     211            $api->set_session( $key );
     212        }
     213
    212214        /**
    213215         * If user is not authorized, return auth flow URL for them in the response
     
    215217         */
    216218        if ( ! $api->is_user_authorized() ) {
    217             /**
    218              * Set data to store in the cookie so we can redirect user and
    219              * continue their flow.
    220              */
     219            // Reset session if in AMP context as we want to pair data to AMP client ID instead.
     220            if ( $is_amp ) {
     221                $api->set_session( '' );
     222
     223                $amp_id_key = '';
     224
     225                if ( $is_amp ) {
     226                    $amp_id_key = $key;
     227                }
     228            }
     229
     230            $auth_url = $api::$auth->get_auth_code_url();
     231            $state    = $api::$auth->get_state_from_auth_url( $auth_url );
     232
     233            $api->set_session( $state );
     234
     235            $redirect_uri = $redirect_uri;
     236
     237            // Set specific AMP redirect URI to redirect back to AMP context.
     238            if ( $is_amp ) {
     239                $redirect_uri = add_query_arg(
     240                    [
     241                        'amp'     => 1,
     242                        'session' => $state,
     243                    ],
     244                    $redirect_uri
     245                );
     246            }
     247
    221248            $client_data = [
    222249                'redirect_uri' => $redirect_uri,
    223                 'contribution' => [
    224                     'amount'  => number_format( $amount, 2 ),
    225                     'item_id' => $item_id,
    226                 ],
    227250            ];
    228251
    229             // Store data to a cookie.
    230             API::set_user_cookie( $client_data );
     252            // Add reference to AMP client ID to client meta for future linking.
     253            if ( $is_amp ) {
     254                $client_data['amp_id_key'] = $amp_id_key;
     255            }
     256
     257            $api->set_client_meta( $client_data );
     258
     259            if ( $is_amp ) {
     260                header( 'AMP-Redirect-To: ' . $auth_url );
     261                header( 'Access-Control-Expose-Headers: AMP-Redirect-To' );
     262            }
    231263
    232264            // Send JSON response with auth code flow URL and 401 code.
     
    234266                [
    235267                    'data' => [
    236                         'auth_url' => $api::$auth->get_auth_code_url(),
     268                        'auth_url'    => $auth_url,
     269                        'session_key' => $api->session_key,
     270                        'handover'    => [
     271                            'contribution' => [
     272                                'amount'  => number_format( $amount, 2 ),
     273                                'item_id' => $item_id,
     274                            ],
     275                        ],
    237276                    ],
    238277                ],
     
    277316
    278317            if ( $is_amp ) {
    279                 setcookie(
    280                     static::AMP_TAB_DATA_COOKIE_NAME,
    281                     json_encode( $tab_data ),
    282                     [
    283                         'path'   => '/',
    284                         'secure' => is_ssl(),
    285                     ]
    286                 );
     318                $api->set_client_meta( $tab_data, 'amp_payment' );
    287319            }
    288320
     
    310342                );
    311343
    312                 API::unset_user_cookie();
    313 
    314344                wp_send_json(
    315345                    $response,
     
    325355             */
    326356            case 402:
    327                 $credentials = $api::$auth->get_credentials();
    328 
    329                 // Set cookie with full tab ID to use when redirecting.
    330                 $api::set_full_tab_cookie( $response['data']['tab']['id'] );
    331 
    332357                $iframe_url = static::get_payment_iframe_url();
    333 
    334358                $iframe_url = add_query_arg(
    335359                    [
    336                         'layout_type' => $layout_type,
     360                        'key' => $key,
     361                        'v'   => time(),
    337362                    ],
    338363                    $iframe_url
    339364                );
     365
     366                $meta = [
     367                    'tab_id'      => $tab_data['id'],
     368                    'layout_type' => $layout_type,
     369                ];
     370
     371                // Store full tab ID and layout type in payment meta.
     372                $api->set_client_meta( $meta, 'payment' );
    340373
    341374                $response['data']['payment_required'] = true;
     
    347380                );
    348381
    349                 API::unset_user_cookie();
    350 
    351382                wp_send_json(
    352383                    $response,
     
    413444
    414445    /**
    415      * Get iframe URL for purchase component display (AMP).
    416      *
    417      * @return string
    418      */
    419     public static function get_purchase_iframe_url() {
    420         $url = site_url();
    421         $url = add_query_arg( 'laterpay', 'purchase', $url );
    422 
    423         return $url;
    424     }
    425 
    426     /**
    427446     * Intercept request. When `?laterpay` is present and set to `payment`,
    428447     * make a call to payment component and render it before WP theme initializes.
     
    439458        }
    440459
    441         $layout_type = '';
    442 
    443         if ( isset( $_GET['layout_type'] ) ) {
    444             $layout_type = sanitize_text_field( $_GET['layout_type'] );
    445         }
    446 
    447         $api    = API::get_instance();
    448         $tab_id = $api::get_full_tab_cookie();
     460        if ( ! isset( $_GET['key'] ) ) {
     461            return;
     462        }
     463
     464        $key = sanitize_text_field( $_GET['key'] );
     465
     466        if ( empty( $key ) ) {
     467            return;
     468        }
     469
     470        $api = API::get_instance();
     471        $api->set_session( $key );
     472
     473        // Get full tab ID and layout type previously set to client meta.
     474        $payment_data = $api->get_client_meta( 'payment' );
    449475
    450476        $req = wp_remote_get(
     
    453479                'headers' => [
    454480                    'x-lp-access-token'  => $api::$auth->get_access_token(),
    455                     'x-lp-tab-id'        => $tab_id,
    456                     'x-lp-amp'           => ( function_exists( 'is_amp' ) && is_amp() ),
    457                     'x-lp-theme'         => $layout_type,
     481                    'x-lp-tab-id'        => $payment_data['tab_id'],
     482                    'x-lp-amp'           => ( isset( $_GET['amp'] ) ),
     483                    'x-lp-theme'         => $payment_data['layout_type'],
    458484                ],
    459485            ]
     
    462488        $res = wp_remote_retrieve_body( $req );
    463489
     490        header( 'Access-Control-Allow-Origin: ' . site_url() );
    464491        header( 'Content-Type: text/html; charset=UTF-8' );
    465492
    466493        echo $res; // phpcs:ignore -- WordPress.Security.EscapeOutput.OutputNotEscaped
     494
     495        // Clean up. Delete client meta and payment meta.
     496        $api->delete_client_meta();
     497        $api->delete_client_meta( 'payment' );
    467498
    468499        exit();
     
    482513            return;
    483514        }
     515
     516        if ( ! isset( $_GET['key'] ) ) {
     517            return;
     518        }
     519
     520        $key = sanitize_text_field( $_GET['key'] );
     521
     522        $api = API::get_instance();
     523        $api->set_session( $key );
     524
     525        $amp_meta = $api->get_client_meta( 'amp_payment' );
    484526
    485527        $api      = API::get_instance();
     
    491533        ];
    492534
    493         if ( isset( $_COOKIE[ static::AMP_TAB_DATA_COOKIE_NAME ] ) ) {
    494             $tab_data = wp_parse_args(
    495                 json_decode(
    496                     stripslashes( $_COOKIE[ static::AMP_TAB_DATA_COOKIE_NAME ] ) // phpcs:ignore -- WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    497                 ),
    498                 $tab_data
    499             );
    500         }
     535        $tab_data = wp_parse_args( $amp_meta, $tab_data );
    501536
    502537        // Data to use in the template.
     
    515550    }
    516551
     552    /**
     553     * Outputs simple URL where we'll listen to and intercept the request
     554     * to render a JSON.
     555     *
     556     * @param string $type Type of the JSON to echo.
     557     *
     558     * @return string
     559     */
     560    public static function get_json_amp_url( $type = '' ) {
     561        if ( empty( $type ) ) {
     562            return;
     563        }
     564
     565        $url = add_query_arg(
     566            [
     567                'laterpay' => 'json',
     568                'type'     => $type,
     569            ],
     570            site_url()
     571        );
     572
     573        return $url;
     574    }
     575
     576    /**
     577     * Intercept the request and output JSON with the URL to either purchase
     578     * or payment component for AMP purposes.
     579     *
     580     * AMP implementation uses `<amp-list>` to grab values of this JSON and
     581     * then dynamically renders `<iframe>` with `src` coming from this JSON.
     582     * This allows us to render iframe with the URL queries we need and
     583     * overcome the limitation of `<amp-iframe>` alone which does not allow
     584     * for dynamic attributes by default.
     585     *
     586     * @return string
     587     */
     588    public function handle_json_amp_url() {
     589        if ( ! isset( $_GET['laterpay'] ) ) {
     590            return;
     591        }
     592
     593        if ( 'json' !== sanitize_text_field( $_GET['laterpay'] ) ) {
     594            return;
     595        }
     596
     597        if ( ! isset( $_GET['type'] ) ) {
     598            return;
     599        }
     600
     601        if ( ! isset( $_GET['key'] ) ) {
     602            return;
     603        }
     604
     605        $type = sanitize_text_field( $_GET['type'] );
     606        $key  = sanitize_text_field( $_GET['key'] );
     607
     608        header( 'Content-type: application/json' );
     609
     610        $url = self::get_payment_iframe_url();
     611
     612        $url = add_query_arg(
     613            [
     614                'key' => $key,
     615                'amp' => 1,
     616            ],
     617            $url
     618        );
     619
     620        $json = json_encode(
     621            [
     622                'items' => [
     623                    [
     624                        'url' => $url,
     625                    ],
     626                ],
     627            ]
     628        );
     629
     630        echo $json; // phpcs:ignore -- WordPress.Security.EscapeOutput.OutputNotEscaped -- output is formed in this method so no need to further escape
     631
     632        exit();
     633    }
     634
     635    /**
     636     * Print AMP purchase component script if in AMP context.
     637     *
     638     * @hooked action `wp_print_footer_scripts`
     639     */
     640    public function print_amp_script() {
     641        if ( ! function_exists( 'is_amp_endpoint' ) || ! is_amp_endpoint() ) {
     642            return;
     643        }
     644
     645        include REVENUE_GENERATOR_PLUGIN_DIR . '/v2/templates/frontend/contribution/amp-purchase-component.php';
     646    }
     647
     648    /**
     649     * Print AMP purchase component script hash to wp_head if
     650     * in AMP context.
     651     *
     652     * @hooked action `wp_head`
     653     */
     654    public function add_amp_script_hash() {
     655        if ( ! function_exists( 'is_amp_endpoint' ) || ! is_amp_endpoint() ) {
     656            return;
     657        }
     658        ?>
     659        <meta name="amp-script-src" content="sha384-Xcsn0uFdGgT5Rk2GgmeML-rKQU6kfiRtPfrouuTo0sjizpodOzkcwzV8uBn2zyo9">
     660        <?php
     661    }
     662
    517663}
  • revenue-generator/tags/2.0.1/v2/templates/frontend/contribution/partial-amounts.php

    r2466307 r2468562  
    1313global $wp;
    1414?>
     15
     16<?php
     17/**
     18 * The following bit is added so that AMP compiled CSS include
     19 * the purchase component styles which is not yet available
     20 * in DOM at the time of render.
     21 */
     22?>
     23<?php if ( $is_amp ) : ?>
     24    <div class="tab_widget__container tab_widget__arc-container tab_widget__arc--background tab_widget__arc--filled tab_widget__donated-amount-text tab_widget__thank-you-message tab_widget__links-container tab_widget__link tab_widget__links-separator tab_widget__container-hidden tab_widget__container-visible tab_widget__regular-text tab_widget tab_widget__arc-animation lp__root lp__tab-widget-data tab__widget__info-button__container tab__widget__info-button tab__widget__info-button-question-mark tab__widget__close-button-x-mark tab_widget__container__info-screen infoContainer title steps step stepText stepNumber description tab__widget__icon" style="display: none;"></div>
     25<?php endif; ?>
     26
    1527<div class="rev-gen-contribution__donate" id="<?php echo esc_attr( $html_id ); ?>_donate">
    1628    <form class="rev-gen-contribution__form" action="<?php echo esc_url( admin_url() ); ?>admin-ajax.php" method="POST" id="<?php echo esc_attr( $html_id ); ?>_donate-form" action-xhr="<?php echo esc_url( admin_url() ); ?>admin-ajax.php" data-tab-widget-url="<?php echo esc_url( Frontend_Post::get_tab_widget_script_url() ); ?>" on="submit:AMP.setState({ submitted: 1, submitting: 1 })">
     
    1830        <div submit-success>
    1931            <span on="tap:<?php echo esc_attr( $html_id ); ?>_info-modal.show" class="rev-gen-contribution__amp-show-modal"></span>
    20             <iframe src="<?php echo esc_url( Frontend_Post::get_purchase_iframe_url() ); ?>" height="105"></iframe>
     32            <template type="amp-mustache">
     33                <amp-script layout="fixed" height="105" width="330" script="revenue-generator-amp-purchase-component">
     34                    <div class="lp__root">
     35                        <div class="lp__tab-widget-data"
     36                        data-tab-amount="{{ data.tab.total }}"
     37                        data-tab-currency="USD"
     38                        data-tab-limit="{{ data.tab.limit }}"
     39                        data-view-tab-url="https://mytab.laterpay.net"></div>
     40                    </div>
     41                </amp-script>
     42            </template>
    2143        </div>
    2244        <div submit-error>
    2345            <span on="tap:<?php echo esc_attr( $html_id ); ?>_info-modal.show" class="rev-gen-contribution__amp-show-modal--purchase"></span>
    24             <iframe src="<?php echo esc_url( Frontend_Post::get_payment_iframe_url() ); ?>" height="250"></iframe>
     46            <amp-list width="auto" height="250" src="<?php echo esc_url( Frontend_Post::get_json_amp_url( 'payment' ) ); ?>&key=CLIENT_ID(uid)" max-items="1">
     47                <template type="amp-mustache">
     48                    <iframe src="{{url}}" sandbox="allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation-by-user-activation" width="100%" height="250" allowpaymentrequest></iframe>
     49                </template>
     50            </amp-list>
    2551        </div>
    2652        <?php endif; ?>
     
    3157        <input type="hidden" name="action" value="<?php echo esc_attr( Frontend_Post::CONTRIBUTION_AJAX_ACTION ); ?>">
    3258        <?php if ( $is_amp ) : ?>
     59        <input type="hidden" name="rg_key" value="CLIENT_ID(uid)" data-amp-replace="CLIENT_ID">
    3360        <input type="hidden" name="is_amp" value="1">
    3461        <?php endif; ?>
  • revenue-generator/tags/2.0.1/vendor/autoload.php

    r2466307 r2468562  
    55require_once __DIR__ . '/composer/autoload_real.php';
    66
    7 return ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b::getLoader();
     7return ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045::getLoader();
  • revenue-generator/tags/2.0.1/vendor/composer/InstalledVersions.php

    r2466307 r2468562  
    2525  'root' =>
    2626  array (
    27     'pretty_version' => '2.0.0',
    28     'version' => '2.0.0.0',
     27    'pretty_version' => '2.0.1',
     28    'version' => '2.0.1.0',
    2929    'aliases' =>
    3030    array (
     
    7373    'laterpay/revenue-generator' =>
    7474    array (
    75       'pretty_version' => '2.0.0',
    76       'version' => '2.0.0.0',
     75      'pretty_version' => '2.0.1',
     76      'version' => '2.0.1.0',
    7777      'aliases' =>
    7878      array (
  • revenue-generator/tags/2.0.1/vendor/composer/autoload_real.php

    r2466307 r2468562  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b
     5class ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
    29         spl_autoload_unregister(array('ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045', 'loadClassLoader'));
    3030
    3131        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
     
    3333            require __DIR__ . '/autoload_static.php';
    3434
    35             call_user_func(\Composer\Autoload\ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::getInitializer($loader));
     35            call_user_func(\Composer\Autoload\ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::getInitializer($loader));
    3636        } else {
    3737            $map = require __DIR__ . '/autoload_namespaces.php';
     
    5454
    5555        if ($useStaticLoader) {
    56             $includeFiles = Composer\Autoload\ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$files;
     56            $includeFiles = Composer\Autoload\ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$files;
    5757        } else {
    5858            $includeFiles = require __DIR__ . '/autoload_files.php';
    5959        }
    6060        foreach ($includeFiles as $fileIdentifier => $file) {
    61             composerRequire1f8be73ed8b3d6b4c601375036a77c9b($fileIdentifier, $file);
     61            composerRequire0180107ac78f1fe5f7e96ac594582045($fileIdentifier, $file);
    6262        }
    6363
     
    6666}
    6767
    68 function composerRequire1f8be73ed8b3d6b4c601375036a77c9b($fileIdentifier, $file)
     68function composerRequire0180107ac78f1fe5f7e96ac594582045($fileIdentifier, $file)
    6969{
    7070    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  • revenue-generator/tags/2.0.1/vendor/composer/autoload_static.php

    r2466307 r2468562  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b
     7class ComposerStaticInit0180107ac78f1fe5f7e96ac594582045
    88{
    99    public static $files = array (
     
    198198    {
    199199        return \Closure::bind(function () use ($loader) {
    200             $loader->prefixLengthsPsr4 = ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$prefixLengthsPsr4;
    201             $loader->prefixDirsPsr4 = ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$prefixDirsPsr4;
    202             $loader->classMap = ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$classMap;
     200            $loader->prefixLengthsPsr4 = ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$prefixLengthsPsr4;
     201            $loader->prefixDirsPsr4 = ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$prefixDirsPsr4;
     202            $loader->classMap = ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$classMap;
    203203
    204204        }, null, ClassLoader::class);
  • revenue-generator/tags/2.0.1/vendor/composer/installed.php

    r2466307 r2468562  
    22  'root' =>
    33  array (
    4     'pretty_version' => '2.0.0',
    5     'version' => '2.0.0.0',
     4    'pretty_version' => '2.0.1',
     5    'version' => '2.0.1.0',
    66    'aliases' =>
    77    array (
     
    5050    'laterpay/revenue-generator' =>
    5151    array (
    52       'pretty_version' => '2.0.0',
    53       'version' => '2.0.0.0',
     52      'pretty_version' => '2.0.1',
     53      'version' => '2.0.1.0',
    5454      'aliases' =>
    5555      array (
  • revenue-generator/trunk/languages/revenue-generator.po

    r2466307 r2468562  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Revenue Generator 2.0.0\n"
     5"Project-Id-Version: Revenue Generator 2.0.1\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/revenue-generator\n"
    77"Last-Translator: Kimberly Moore <[email protected]>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2021-02-01T09:02:16+00:00\n"
     12"POT-Creation-Date: 2021-02-04T08:24:31+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.4.0\n"
     
    403403
    404404#: v1/inc/classes/class-frontend-post.php:780
    405 #: v2/inc/classes/class-frontend-post.php:194
     405#: v2/inc/classes/class-frontend-post.php:191
    406406msgid "Contribution amount cannot be empty."
    407407msgstr ""
     
    13571357
    13581358#: v1/templates/frontend/contribution/partial-custom.php:35
    1359 #: v2/templates/frontend/contribution/partial-amounts.php:71
     1359#: v2/templates/frontend/contribution/partial-amounts.php:98
    13601360msgid "Enter custom amount"
    13611361msgstr ""
     
    13661366
    13671367#: v1/templates/frontend/contribution/partial-donate.php:37
    1368 #: v2/templates/frontend/contribution/partial-amounts.php:62
     1368#: v2/templates/frontend/contribution/partial-amounts.php:89
    13691369msgid "Custom"
    13701370msgstr ""
    13711371
    1372 #: v2/inc/classes/class-frontend-post.php:201
     1372#: v2/inc/classes/class-frontend-post.php:198
    13731373msgid "Contribution details cannot be empty."
    13741374msgstr ""
     
    14311431msgstr ""
    14321432
    1433 #: v2/templates/frontend/contribution/partial-amounts.php:72
     1433#: v2/templates/frontend/contribution/partial-amounts.php:99
    14341434msgid "Send"
    14351435msgstr ""
    14361436
    1437 #: v2/templates/frontend/contribution/partial-amounts.php:76
     1437#: v2/templates/frontend/contribution/partial-amounts.php:103
    14381438msgid "Add to MyTab"
    14391439msgstr ""
  • revenue-generator/trunk/readme.txt

    r2466307 r2468562  
    77Tested up to: 5.6
    88Requires PHP: 5.6
    9 Stable tag: 2.0.0
     9Stable tag: 2.0.1
    1010Author URI: https://laterpay.net
    1111Plugin URI: https://github.com/laterpay/revenue-generator/
     
    8282== Changelog ==
    8383
     84= 2.0.1 ( 4 February 2021 ) =
     85* Fixed issue with contributions on page cache enabled hosts.
     86
    8487= 2.0.0 ( 1 February 2021 ) =
    8588* New for contributions-only merchants: on-page purchase and payment experience powered by all new Laterpay platform.
     
    126129== Upgrade notice ==
    127130
     131= 2.0.1 =
     132Fixed issue with contributions on page cache enabled hosts.
     133
    128134= 2.0.0 =
    129135New on-page purchase and payment experience for contributions-only merchants. Added support for custom post types to paywalls.
  • revenue-generator/trunk/revenue-generator.php

    r2466307 r2468562  
    44 * Description: Monetize your blog and content with Laterpay's Revenue Generator.
    55 * Plugin URI: https://github.com/laterpay/revenue-generator
    6  * Version: 2.0.0
     6 * Version: 2.0.1
    77 * Author: Laterpay
    88 * Text Domain: revenue-generator
     
    1515defined( 'ABSPATH' ) || exit;
    1616
    17 define( 'REVENUE_GENERATOR_VERSION', '2.0.0' );
     17define( 'REVENUE_GENERATOR_VERSION', '2.0.1' );
    1818
    1919if ( ! defined( 'REVENUE_GENERATOR_PLUGIN_FILE' ) ) {
  • revenue-generator/trunk/v2/assets/build/css/frontend.css

    r2466307 r2468562  
    1 .amount-text,.rev-gen-contribution__amount{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:600;line-height:1.21;text-align:center;color:#333}.rev-gen-contribution{position:relative;width:100%;margin:20px auto;height:auto;transition:height 0.2s ease-in}.rev-gen-contribution__inner{position:relative;height:100%;padding:18px 25px;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:250px}.rev-gen-contribution__question-mark,.rev-gen-contribution-info-modal__x-mark{position:absolute;top:10px;right:10px;z-index:20;cursor:pointer;width:18px;height:18px;border-radius:50%;font-weight:700;font-size:12px;background-color:#1d1d1d;color:#fff;text-align:center}.rev-gen-contribution__question-mark span,.rev-gen-contribution-info-modal__x-mark span{position:relative;left:1px}.rev-gen-contribution-modal .rev-gen-contribution__question-mark,.rev-gen-contribution-modal .rev-gen-contribution-info-modal__x-mark{top:13px;right:35px}.rev-gen-contribution-info-modal{position:absolute;top:0;left:0;z-index:50;padding:20px;border-radius:5px;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution-info-modal__x-mark span{position:relative;top:-1px}.rev-gen-contribution-info-modal__title{margin:0;font-weight:500;font-size:18px}.rev-gen-contribution-info-modal__steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.rev-gen-contribution-info-modal__step{display:flex;align-items:center;margin:0;font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__step-text{margin-left:6px;margin-right:10px}.rev-gen-contribution-info-modal__step-number{display:flex;align-items:center;justify-content:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.rev-gen-contribution-info-modal__description{font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__description p{margin-bottom:1em}.rev-gen-contribution-info-modal__description p:last-child{margin-bottom:0}.rev-gen-contribution h2.rev-gen-contribution__title{margin:0;max-width:100%;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:bold;line-height:1.33;font-size:21px;text-align:center;color:#1d1d1d}.rev-gen-contribution h2.rev-gen-contribution__title::before,.rev-gen-contribution h2.rev-gen-contribution__title::after{display:none !important}.rev-gen-contribution__description{max-width:100%;font-size:14px;text-align:center}.rev-gen-contribution__amounts{display:flex;flex-flow:row nowrap;justify-content:space-between;margin-bottom:20px}.rev-gen-contribution--bar .rev-gen-contribution__amounts{justify-content:center}.rev-gen-contribution__form{margin:20px 0}.rev-gen-contribution__form.amp-form-submit-success,.rev-gen-contribution__form.amp-form-submit-error{margin:0}.rev-gen-contribution__form button[type="submit"]{max-width:100%;flex:0 1 100%;width:100%;padding:15px 0;font-size:15px;border:1px solid #000;border-radius:4px;font-weight:500;background:#1d1d1d !important;color:#fff !important;text-decoration:none;text-transform:none;text-shadow:none}.rev-gen-contribution__form button[type="submit"].show{display:block}.rev-gen-contribution .rev-gen-hidden{display:none}.rev-gen-contribution__amount{min-width:75px;border:solid 2px #1d1d1d;border-radius:5px;margin:0 2px;display:flex;align-items:center;text-align:center;justify-content:center;overflow:hidden;cursor:pointer;word-break:normal;color:#1d1d1d;background-color:#fff}.rev-gen-contribution__amount input{position:absolute;opacity:0;width:0;height:0}.rev-gen-contribution__amount--custom{outline:0;text-transform:none;text-decoration:none}.rev-gen-contribution__amount--custom:hover,.rev-gen-contribution__amount--custom:active,.rev-gen-contribution__amount--custom:focus{background:#1d1d1d !important;color:#fff !important;text-decoration:none}.rev-gen-contribution__amount .rev-gen-contribution-control__label{display:block;width:100%;height:100%;border:0;padding:15px;font-size:14px;background:#fff !important;color:#1d1d1d !important;box-shadow:none !important;transition:background-color 0.05s ease-in !important;text-decoration:none !important;text-transform:none !important;letter-spacing:0 !important}.rev-gen-contribution__amount .rev-gen-contribution-control__label:hover{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount input:checked+.rev-gen-contribution-control__label{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount-wrapper{position:relative;display:flex;justify-content:center}.rev-gen-contribution__tip{margin:0 0 5px;line-height:1;font-size:13px;text-align:center}.rev-gen-contribution__tip.rev-gen-hidden{visibility:hidden}.rev-gen-contribution__custom input[type="number"]{min-width:220px;margin-right:5px;padding:13.5px 0 13px 15px;border-radius:5px;background-color:rgba(160,160,160,0.12);margin-bottom:10px;font-size:14px;outline:0;border:0}.rev-gen-contribution__custom.rev-gen-hidden:not[hidden]{display:none}.rev-gen-contribution__tab-status{height:100%;font-size:14px;text-align:center;transition:min-height 0.2s ease-in}.rev-gen-contribution__tab-status iframe{width:100%;height:0;margin:0 !important;padding:0 !important;border:0 !important}.rev-gen-contribution__response{position:relative;z-index:2;width:100%;background-color:#fff}.rev-gen-contribution__loading{position:absolute;z-index:1;top:50%;margin-top:-32px;left:50%;margin-left:-38px}.rev-gen-contribution-custom{max-width:335px;margin:10px auto;display:flex;flex-flow:row nowrap;align-items:center}.rev-gen-contribution-custom__group{flex:1;display:flex;flex-flow:row nowrap}.rev-gen-contribution-custom__inner{display:flex;flex-flow:row nowrap;align-items:flex-end;justify-content:space-between}.rev-gen-contribution-custom__form{display:flex;align-items:flex-end}.rev-gen-contribution-custom h3.rev-gen-contribution-custom__title{margin:0;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;line-height:1.33;font-size:14px;color:#1d1d1d}.rev-gen-contribution-custom__back{position:relative;bottom:5px;float:left;cursor:pointer;width:15px;margin-right:15px}.rev-gen-contribution-custom__back-arrow{display:inline-block;vertical-align:middle;border:solid #000;border-width:0 2px 2px 0;padding:14px;transform:rotate(135deg)}.rev-gen-contribution-custom__symbol{width:15px;text-align:center}.rev-gen-contribution-custom label{display:block;margin-left:15px;margin-bottom:5px;line-height:1;font-weight:normal;font-size:12px}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send{flex:1;width:auto;min-width:70px;max-width:none;max-height:49px;margin:0;padding:14px 10px !important;border:2px solid #1d1d1d !important;border-radius:5px;font-weight:700;font-size:14px;color:#1d1d1d !important;background-color:#fff !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:active,.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:hover{color:#fff !important;background-color:#1d1d1d !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:disabled{opacity:0.8}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send .rev-gen-contribution-custom-send__loading{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading{padding:11px 10px !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__text{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__loading{display:inline-block;width:21px;height:21px;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMiIgYmFzZVByb2ZpbGU9InRpbnkiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgoJIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTAwIDUwMCIgb3ZlcmZsb3c9InZpc2libGUiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGZpbGw9IiNmZmZmZmYiIGQ9Ik0zMTcsNDc5LjRjLTEyLDAtMjMuMy03LjYtMjcuNC0xOS42Yy01LjItMTUuMSwyLjktMzEuNiwxOC0zNi44YzcxLjUtMjQuNiwxMTkuNS05MS45LDExOS41LTE2Ny41CgkJYzAtOTcuNi03OS40LTE3Ny4xLTE3Ny4xLTE3Ny4xUzcyLjksMTU3LjksNzIuOSwyNTUuNmMwLDc1LjYsNDgsMTQzLDExOS41LDE2Ny41YzE1LjEsNS4yLDIzLjIsMjEuNywxOCwzNi44cy0yMS43LDIzLjItMzYuOCwxOAoJCUM3OC43LDQ0NS4zLDE1LDM1NS45LDE1LDI1NS42YzAtMTI5LjYsMTA1LjQtMjM1LDIzNS0yMzVzMjM1LDEwNS40LDIzNSwyMzVjMCwxMDAuNC02My43LDE4OS43LTE1OC42LDIyMi4zCgkJQzMyMy4zLDQ3OC45LDMyMC4xLDQ3OS40LDMxNyw0NzkuNHoiLz4KPC9nPgo8L3N2Zz4K) no-repeat;background-size:21px 21px;transition:transform 0.2s ease-in-out;-webkit-animation:pulse-loading 1s infinite;animation:pulse-loading 1s infinite}.rev-gen-contribution-footer{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif}.rev-gen-contribution-footer__inner{display:flex;align-items:center;justify-content:center}.rev-gen-contribution-footer a{flex:1;margin-left:5px;max-width:75px;opacity:0.6;transition:opacity 0.2s ease-in}.rev-gen-contribution-footer a:hover{opacity:1}.rev-gen-contribution-footer a img{vertical-align:middle}.rev-gen-contribution-footer span{position:relative;top:2px;line-height:1.1;font-size:11px;color:#808080}.rev-gen-contribution--box{max-width:380px !important}.rev-gen-contribution--bar{width:100%}.rev-gen-contribution--bar .rev-gen-contribution__donate{margin:15px 0 5px}.rev-gen-contribution--bar .rev-gen-contribution__inner{max-width:100%;padding:15px 25px}.rev-gen-contribution--bar.size-large h2.rev-gen-contribution__title{min-width:250px;margin-right:15px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__inner{padding:0 25px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__choose{display:flex;align-items:center}.rev-gen-contribution--bar.size-large .rev-gen-contribution__description{min-width:250px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form{margin:15px 0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form button[type="submit"]{width:300px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__amounts{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__donate{align-self:flex-end;margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-info-modal{left:auto;right:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom{margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom label{display:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom__back{bottom:auto;float:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom input[type="number"]{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom button[type="submit"]{width:auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution__loading{transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response{display:flex;align-items:center;transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response .tab_widget__container{height:85px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer{margin-left:15px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer a{width:75px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__tab-status{position:relative;min-width:250px;height:85px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__loading{left:0;margin-left:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__response{height:100%;overflow:hidden;margin-right:10px;transform:none;background-color:transparent}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution iframe{height:85px !important}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution-footer{display:none}.rev-gen-contribution--bar.size-large.amount-selected .rev-gen-contribution__amounts{display:none}.rev-gen-contribution--bar.size-large.rev-gen-iframe-ready iframe{width:600px}.rev-gen-contribution--button .rev-gen-contribution__inner{padding:0;box-shadow:none;background-color:transparent;text-align:center}.rev-gen-contribution--button .rev-gen-contribution__footer{margin-top:15px}.rev-gen-contribution--button .rev-gen-contribution__button{max-width:320px;padding:15px 30px;border:0;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:16px;color:#fff;background-color:#1d1d1d;text-decoration:none}.rev-gen-contribution--button .rev-gen-contribution__button:hover,.rev-gen-contribution--button .rev-gen-contribution__button:active{border:0;box-shadow:none;text-decoration:none}.rev-gen-contribution--button:not(.is-amp) .rev-gen-contribution-modal{display:none}.rev-gen-contribution.is-amp iframe{position:relative;z-index:15}.rev-gen-contribution .amp-form-submit-success>*{display:none}.rev-gen-contribution .amp-form-submitting{height:100px}.rev-gen-contribution__amp-show-modal,.rev-gen-contribution__amp-show-modal--purchase{position:absolute;bottom:35px;left:165px;z-index:10;width:95px;height:20px;display:block;background:transparent;cursor:pointer}.rev-gen-contribution__amp-show-modal--purchase{top:72px;bottom:auto}.rev-gen-contribution-modal{position:fixed;top:0;left:0;z-index:9999;display:flex;align-items:center;width:100%;height:100%;background-color:rgba(0,0,0,0.5);opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution{opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution__inner{padding:30px 25px 18px;background-color:#fff}.rev-gen-contribution-modal.active{opacity:1}.rev-gen-contribution-modal.active .rev-gen-contribution{opacity:1}.rev-gen-contribution-modal__close{position:absolute;top:15px;right:15px;display:inline-block;width:15px;height:15px;padding:0 !important;border:0 !important;background:transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMyIgaGVpZ2h0PSIxMyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDEzIDEzIj4KICAgIDxwYXRoIGZpbGw9IiMxRDFEMUQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTguMDMyIDYuNUwxMyAxLjUzMSAxMS40NjggMCA2LjUgNC45NjggMS41MzIgMCAwIDEuNTMybDQuOTY4IDQuOTY3TDAgMTEuNDY3bDEuNTMyIDEuNTMyTDYuNSA4LjAzbDQuOTY4IDQuOTY4TDEzIDExLjQ2NyA4LjAzMiA2LjQ5OXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPgo8L3N2Zz4K) no-repeat !important;background-size:15px 15px !important;opacity:0.35}.is-amp .rev-gen-contribution-modal{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution-amp-wrap{display:flex;width:100%;height:100%;align-items:center}@-webkit-keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}.font,.tab_widget__donated-amount-text,.tab_widget__thank-you-message,.tab_widget__regular-text,.tab_widget__link,.tab__widget__info-button-question-mark,.tab_widget__info_container{font-family:"Helvetica Neue", Arial, Helvetica, sans-serif}.tab_widget{display:flex;justify-content:center;align-items:center;height:100%}.tab_widget__container{position:relative;background-color:#fff;border-radius:6px;display:flex;align-items:center;width:340px;height:104px;transition:transform 0.5s linear}.tab_widget__container-visible{transform:translate(0)}.tab_widget__arc-container{margin-right:6px;width:calc(64px + 6px);height:64px;position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:center}.tab_widget__arc--background{position:absolute;stroke:#cbd5e0}.tab_widget__arc--filled{position:absolute;stroke:#000;stroke-dasharray:175.84;stroke-dashoffset:175.84}.tab_widget__arc-animation{-webkit-animation:animateTabAmount 0.5s linear forwards;animation:animateTabAmount 0.5s linear forwards}.tab_widget__arc-animation--pulse{stroke:#000;animation:pulse 1s ease-in-out alternate-reverse infinite}.tab_widget__arc-animation--pulse circle{stroke:#000;stroke-opacity:inherit}@-webkit-keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@-webkit-keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}@keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}.tab_widget__donated-amount-text{font-weight:700}.tab_widget__thank-you-message{font-weight:500;margin:0;margin-bottom:5px;font-size:19px;color:#1d1d1d;text-align:left}.tab_widget__regular-text{font-weight:400;font-size:15px;margin:0;margin-bottom:5px;color:#333}.tab_widget__links-container{display:flex;align-items:center}.tab_widget__link{font-weight:400;margin:0;font-size:13px;color:#1d1d1d;text-decoration:underline;cursor:pointer}.tab_widget__links-separator{padding-right:5px;padding-left:5px;color:#333}.tab_widget__container-hidden{transform:translate(500px)}.tab__widget__info-button__container{position:absolute;right:6px;top:6px;cursor:pointer}.tab__widget__info-button{position:relative}.tab__widget__info-button-question-mark{position:absolute;font-weight:700;font-size:12px;color:#fff;left:34%;top:0}.tab__widget__close-button-x-mark{left:33%;top:-1px}.tab_widget__container__info-screen{position:absolute;height:100%;width:calc(100% + 50px);margin-top:-35px;margin-left:-25px;z-index:10;visibility:var(--infoScreenVisibility);text-align:left}.tab_widget__info_container{position:relative;padding:20px;background-color:#fff;box-shadow:0 1px 8px 0 rgba(29,29,29,0.16);border-radius:6px}.tab_widget__info-title{font-weight:500;font-size:18px;margin:0}.tab_widget__info-steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.tab_widget__info-step{display:flex;align-items:center;font-weight:500;font-size:14px;margin:0}.tab_widget__info-step-text{margin-left:6px;margin-right:10px}.tab_widget__info-step-number{display:flex;justify-content:center;align-items:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.tab_widget__info-description{font-weight:500;font-size:14px}.tab_widget__info-description p{margin-bottom:1em}.tab_widget__info-description p:last-child{margin-bottom:0}.tab__widget__icon{position:unset;height:18px;width:18px}
     1.amount-text,.rev-gen-contribution__amount{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:600;line-height:1.21;text-align:center;color:#333}.rev-gen-contribution{position:relative;width:100%;margin:20px auto;height:auto;transition:height 0.2s ease-in}.rev-gen-contribution__inner{position:relative;height:100%;padding:18px 25px;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:250px}.rev-gen-contribution__question-mark,.rev-gen-contribution-info-modal__x-mark{position:absolute;top:10px;right:10px;z-index:20;cursor:pointer;width:18px;height:18px;border-radius:50%;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:700;font-size:12px;background-color:#1d1d1d;color:#fff;text-align:center}.rev-gen-contribution__question-mark span,.rev-gen-contribution-info-modal__x-mark span{position:relative;left:1px}.rev-gen-contribution-modal .rev-gen-contribution__question-mark,.rev-gen-contribution-modal .rev-gen-contribution-info-modal__x-mark{top:13px;right:35px}.rev-gen-contribution-info-modal{position:absolute;top:0;left:0;z-index:50;padding:20px;border-radius:5px;box-shadow:0 0 15px 0 rgba(0,0,0,0.1);background-color:#fff}.rev-gen-contribution-info-modal__x-mark span{position:relative;top:-1px}.rev-gen-contribution-info-modal__title{margin:0;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:18px}.rev-gen-contribution-info-modal__steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.rev-gen-contribution-info-modal__step{display:flex;align-items:center;margin:0;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__step-text{margin-left:6px;margin-right:10px}.rev-gen-contribution-info-modal__step-number{display:flex;align-items:center;justify-content:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.rev-gen-contribution-info-modal__description p{margin-bottom:1em;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:14px}.rev-gen-contribution-info-modal__description p:last-child{margin-bottom:0}.rev-gen-contribution h2.rev-gen-contribution__title{margin:0;max-width:100%;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:bold;line-height:1.33;font-size:21px;text-align:center;color:#1d1d1d}.rev-gen-contribution h2.rev-gen-contribution__title::before,.rev-gen-contribution h2.rev-gen-contribution__title::after{display:none !important}.rev-gen-contribution__description{max-width:100%;font-size:14px;text-align:center}.rev-gen-contribution__amounts{display:flex;flex-flow:row nowrap;justify-content:space-between;margin-bottom:20px}.rev-gen-contribution--bar .rev-gen-contribution__amounts{justify-content:center}.rev-gen-contribution__form{margin:20px 0}.rev-gen-contribution__form.amp-form-submit-success,.rev-gen-contribution__form.amp-form-submit-error{max-height:250px;overflow:hidden;margin:0}.rev-gen-contribution__form div[submit-success]{position:relative;z-index:10}.rev-gen-contribution__form button[type="submit"]{cursor:pointer;max-width:100%;flex:0 1 100%;width:100%;padding:15px 0;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:15px;border:1px solid #000;border-radius:4px;font-weight:500;background:#1d1d1d !important;color:#fff !important;text-decoration:none;text-transform:none;text-shadow:none}.rev-gen-contribution__form button[type="submit"].show{display:block}.rev-gen-contribution .rev-gen-hidden{display:none}.rev-gen-contribution__amount{min-width:75px;border:solid 2px #1d1d1d;border-radius:5px;margin:0 2px;display:flex;align-items:center;text-align:center;justify-content:center;overflow:hidden;cursor:pointer;word-break:normal;color:#1d1d1d;background-color:#fff}.rev-gen-contribution__amount input{position:absolute;opacity:0;width:0;height:0}.rev-gen-contribution__amount--custom{outline:0;text-transform:none;text-decoration:none}.rev-gen-contribution__amount--custom:hover,.rev-gen-contribution__amount--custom:active,.rev-gen-contribution__amount--custom:focus{background:#1d1d1d !important;color:#fff !important;text-decoration:none}.rev-gen-contribution__amount .rev-gen-contribution-control__label{display:block;width:100%;height:100%;border:0;padding:15px;font-size:14px;background:#fff !important;color:#1d1d1d !important;box-shadow:none !important;transition:background-color 0.05s ease-in !important;text-decoration:none !important;text-transform:none !important;letter-spacing:0 !important}.rev-gen-contribution__amount .rev-gen-contribution-control__label:hover{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount input:checked+.rev-gen-contribution-control__label{background:#1d1d1d !important;color:#fff !important}.rev-gen-contribution__amount-wrapper{position:relative;display:flex;justify-content:center}.rev-gen-contribution__tip{margin:0 0 5px;line-height:1;font-size:13px;text-align:center}.rev-gen-contribution__tip.rev-gen-hidden{visibility:hidden}.rev-gen-contribution__custom input[type="number"]{min-width:220px;margin:0 5px 0 0;padding:13.5px 0 13px 15px;border-radius:5px;background-color:rgba(160,160,160,0.12);font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;outline:0;border:0}.rev-gen-contribution__custom.rev-gen-hidden:not[hidden]{display:none}.rev-gen-contribution__tab-status{height:100%;font-size:14px;text-align:center;transition:min-height 0.2s ease-in}.rev-gen-contribution__tab-status iframe{width:100%;height:0;margin:0 !important;padding:0 !important;border:0 !important}.rev-gen-contribution__response{position:relative;z-index:2;width:100%;background-color:#fff}.rev-gen-contribution__loading{position:absolute;z-index:1;top:50%;margin-top:-32px;left:50%;margin-left:-38px}.rev-gen-contribution-custom{max-width:335px;margin:10px auto;display:flex;flex-flow:row nowrap;align-items:center}.rev-gen-contribution-custom__group{flex:1;display:flex;flex-flow:row nowrap}.rev-gen-contribution-custom__inner{display:flex;flex-flow:row nowrap;align-items:flex-end;justify-content:space-between}.rev-gen-contribution-custom__form{display:flex;align-items:flex-end}.rev-gen-contribution-custom h3.rev-gen-contribution-custom__title{margin:0;border:1px solid transparent;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;line-height:1.33;font-size:14px;color:#1d1d1d}.rev-gen-contribution-custom__back{position:relative;bottom:0;float:left;cursor:pointer;width:15px;margin-right:15px}.rev-gen-contribution-custom__back-arrow{display:inline-block;vertical-align:middle;border:solid #000;border-width:0 2px 2px 0;padding:14px;transform:rotate(135deg)}.rev-gen-contribution-custom__symbol{width:15px;text-align:center}.rev-gen-contribution-custom label{display:block;margin-left:15px;margin-bottom:5px;line-height:1;font-weight:normal;font-size:12px}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send{flex:1;width:auto;min-width:70px;max-width:none;max-height:49px;margin:0;padding:14px 10px !important;border:2px solid #1d1d1d !important;border-radius:5px;font-weight:700;font-size:14px;color:#1d1d1d !important;background-color:#fff !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:active,.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:hover{color:#fff !important;background-color:#1d1d1d !important;text-decoration:none !important;box-shadow:none !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send:disabled{opacity:0.8}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send .rev-gen-contribution-custom-send__loading{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading{padding:11px 10px !important}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__text{display:none}.rev-gen-contribution-custom button.rev-gen-contribution-custom-send.loading .rev-gen-contribution-send__loading{display:inline-block;width:21px;height:21px;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMiIgYmFzZVByb2ZpbGU9InRpbnkiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgoJIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTAwIDUwMCIgb3ZlcmZsb3c9InZpc2libGUiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGZpbGw9IiNmZmZmZmYiIGQ9Ik0zMTcsNDc5LjRjLTEyLDAtMjMuMy03LjYtMjcuNC0xOS42Yy01LjItMTUuMSwyLjktMzEuNiwxOC0zNi44YzcxLjUtMjQuNiwxMTkuNS05MS45LDExOS41LTE2Ny41CgkJYzAtOTcuNi03OS40LTE3Ny4xLTE3Ny4xLTE3Ny4xUzcyLjksMTU3LjksNzIuOSwyNTUuNmMwLDc1LjYsNDgsMTQzLDExOS41LDE2Ny41YzE1LjEsNS4yLDIzLjIsMjEuNywxOCwzNi44cy0yMS43LDIzLjItMzYuOCwxOAoJCUM3OC43LDQ0NS4zLDE1LDM1NS45LDE1LDI1NS42YzAtMTI5LjYsMTA1LjQtMjM1LDIzNS0yMzVzMjM1LDEwNS40LDIzNSwyMzVjMCwxMDAuNC02My43LDE4OS43LTE1OC42LDIyMi4zCgkJQzMyMy4zLDQ3OC45LDMyMC4xLDQ3OS40LDMxNyw0NzkuNHoiLz4KPC9nPgo8L3N2Zz4K) no-repeat;background-size:21px 21px;transition:transform 0.2s ease-in-out;-webkit-animation:pulse-loading 1s infinite;animation:pulse-loading 1s infinite}.rev-gen-contribution-footer{font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif}.rev-gen-contribution-footer__inner{display:flex;align-items:center;justify-content:center}.rev-gen-contribution-footer a{flex:1;margin-left:5px;max-width:75px;opacity:0.6;transition:opacity 0.2s ease-in}.rev-gen-contribution-footer a:hover{opacity:1}.rev-gen-contribution-footer a img{vertical-align:middle}.rev-gen-contribution-footer span{position:relative;top:2px;line-height:1.1;font-size:11px;color:#808080}.rev-gen-contribution--box{max-width:380px !important}.rev-gen-contribution--bar{width:100%}.rev-gen-contribution--bar .rev-gen-contribution__donate{margin:15px 0 5px}.rev-gen-contribution--bar .rev-gen-contribution__inner{max-width:100%;padding:15px 25px}.rev-gen-contribution--bar.size-large h2.rev-gen-contribution__title{min-width:250px;margin-right:15px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__inner{padding:0 25px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__choose{display:flex;align-items:center}.rev-gen-contribution--bar.size-large .rev-gen-contribution__description{min-width:250px;text-align:left}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form{margin:15px 0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__form button[type="submit"]{width:300px}.rev-gen-contribution--bar.size-large .rev-gen-contribution__amounts{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution__donate{align-self:flex-end;margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-info-modal{left:auto;right:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom{margin:0 0 0 auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom label{display:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom__back{bottom:auto;float:none}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom input[type="number"]{margin-bottom:0}.rev-gen-contribution--bar.size-large .rev-gen-contribution-custom button[type="submit"]{width:auto}.rev-gen-contribution--bar.size-large .rev-gen-contribution__loading{transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response{display:flex;align-items:center;transform:scale(0.85)}.rev-gen-contribution--bar.size-large .rev-gen-contribution__response .tab_widget__container{height:85px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer{margin-left:15px}.rev-gen-contribution--bar.size-large .rev-gen-contribution-footer a{width:75px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__inner{min-height:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__tab-status{position:relative;min-width:250px;height:85px}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__loading{left:0;margin-left:0}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution__response{height:100%;overflow:hidden;margin-right:10px;transform:none;background-color:transparent}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution iframe{height:85px !important}.rev-gen-contribution--bar.size-large.rev-gen-contribution--payment .rev-gen-contribution-footer{display:none}.rev-gen-contribution--bar.size-large.amount-selected .rev-gen-contribution__amounts{display:none}.rev-gen-contribution--bar.size-large.rev-gen-iframe-ready iframe{width:600px}.rev-gen-contribution--button .rev-gen-contribution__inner{padding:0;box-shadow:none;background-color:transparent;text-align:center}.rev-gen-contribution--button .rev-gen-contribution__footer{margin-top:15px}.rev-gen-contribution--button .rev-gen-contribution__button{max-width:320px;padding:15px 30px;border:0;border-radius:5px;font-family:"Helvetica Neue","Open Sans","Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:500;font-size:16px;color:#fff;background-color:#1d1d1d;text-decoration:none}.rev-gen-contribution--button .rev-gen-contribution__button:hover,.rev-gen-contribution--button .rev-gen-contribution__button:active{border:0;box-shadow:none;text-decoration:none}.rev-gen-contribution--button:not(.is-amp) .rev-gen-contribution-modal{display:none}.rev-gen-contribution.is-amp iframe{position:relative;z-index:15}.rev-gen-contribution .amp-form-submit-success>*{display:none}.rev-gen-contribution .amp-form-submitting{height:100px}.rev-gen-contribution__amp-show-modal,.rev-gen-contribution__amp-show-modal--purchase{position:absolute;bottom:19px;left:137px;z-index:10;width:95px;height:20px;display:block;background:transparent;cursor:pointer}.rev-gen-contribution__amp-show-modal--purchase{top:72px;bottom:auto}.rev-gen-contribution-modal{position:fixed;top:0;left:0;z-index:9999;display:flex;align-items:center;width:100%;height:100%;background-color:rgba(0,0,0,0.5);opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution{opacity:0;transition:opacity 0.13s ease-in}.rev-gen-contribution-modal .rev-gen-contribution__inner{padding:30px 25px 18px;background-color:#fff}.rev-gen-contribution-modal.active{opacity:1}.rev-gen-contribution-modal.active .rev-gen-contribution{opacity:1}.rev-gen-contribution-modal__close{position:absolute;top:15px;right:15px;display:inline-block;width:15px;height:15px;padding:0 !important;border:0 !important;background:transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMyIgaGVpZ2h0PSIxMyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDEzIDEzIj4KICAgIDxwYXRoIGZpbGw9IiMxRDFEMUQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTguMDMyIDYuNUwxMyAxLjUzMSAxMS40NjggMCA2LjUgNC45NjggMS41MzIgMCAwIDEuNTMybDQuOTY4IDQuOTY3TDAgMTEuNDY3bDEuNTMyIDEuNTMyTDYuNSA4LjAzbDQuOTY4IDQuOTY4TDEzIDExLjQ2NyA4LjAzMiA2LjQ5OXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPgo8L3N2Zz4K) no-repeat !important;background-size:15px 15px !important;opacity:0.35}.is-amp .rev-gen-contribution-modal{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution{opacity:1}.is-amp .rev-gen-contribution-modal .rev-gen-contribution-amp-wrap{display:flex;width:100%;height:100%;align-items:center}@-webkit-keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes pulse-loading{0%{transform:scale(1.1)}50%{transform:scale(1.15)}75%{transform:scale(1.1)}100%{transform:scale(1)}}.font,.tab_widget__donated-amount-text,.tab_widget__thank-you-message,.tab_widget__regular-text,a.tab_widget__link,.tab__widget__info-button-question-mark,.tab_widget__info_container{font-family:"Helvetica Neue", Arial, Helvetica, sans-serif}.tab_widget{display:flex;justify-content:center;align-items:center;height:100%}.tab_widget__container{position:relative;background-color:#fff;border-radius:6px;display:flex;align-items:center;width:340px;height:104px;transition:transform 0.5s linear}.tab_widget__container-visible{transform:translate(0)}.tab_widget__arc-container{margin-right:6px;width:calc(64px + 6px);height:64px;position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:center}.tab_widget__arc--background{position:absolute;stroke:#cbd5e0}.tab_widget__arc--filled{position:absolute;stroke:#000;stroke-dasharray:175.84;stroke-dashoffset:175.84}.tab_widget__arc-animation{-webkit-animation:animateTabAmount 0.5s linear forwards;animation:animateTabAmount 0.5s linear forwards}.tab_widget__arc-animation--pulse{stroke:#000;animation:pulse 1s ease-in-out alternate-reverse infinite}.tab_widget__arc-animation--pulse circle{stroke:#000;stroke-opacity:inherit}@-webkit-keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@keyframes animateTabAmount{to{stroke-dashoffset:var(--strokeDashOffset)}}@-webkit-keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}@keyframes pulse{0%{stroke-opacity:0.2}100%{transform:scale(1.1)}}.tab_widget__donated-amount-text{font-weight:700}.tab_widget__thank-you-message{font-weight:500;margin:0;margin-bottom:5px;font-size:19px;color:#1d1d1d;text-align:left}.tab_widget__regular-text{font-weight:400;font-size:15px;margin:0;margin-bottom:5px;color:#333}.tab_widget__links-container{display:flex;align-items:center}a.tab_widget__link{font-weight:400;margin:0;font-size:13px;color:#1d1d1d;text-decoration:underline;cursor:pointer}a.tab_widget__link:hover,a.tab_widget__link:visited{color:#1d1d1d}.tab_widget__links-separator{padding-right:5px;padding-left:5px;color:#333}.tab_widget__container-hidden{transform:translate(500px)}.tab__widget__info-button__container{position:absolute;right:6px;top:6px;cursor:pointer}.tab__widget__info-button{position:relative}.tab__widget__info-button-question-mark{position:absolute;font-weight:700;font-size:12px;color:#fff;left:34%;top:0}.tab__widget__close-button-x-mark{left:33%;top:-1px}.tab_widget__container__info-screen{position:absolute;height:100%;width:calc(100% + 50px);margin-top:-35px;margin-left:-25px;z-index:10;visibility:var(--infoScreenVisibility);text-align:left}.tab_widget__info_container{position:relative;padding:20px;background-color:#fff;box-shadow:0 1px 8px 0 rgba(29,29,29,0.16);border-radius:6px}.tab_widget__info-title{font-weight:500;font-size:18px;margin:0}.tab_widget__info-steps{margin-top:18px;margin-bottom:20px;display:flex;align-items:center}.tab_widget__info-step{display:flex;align-items:center;font-weight:500;font-size:14px;margin:0}.tab_widget__info-step-text{margin-left:6px;margin-right:10px}.tab_widget__info-step-number{display:flex;justify-content:center;align-items:center;font-size:10px;width:18px;height:18px;border-radius:50%;background-color:#1d1d1d;color:#fff}.tab_widget__info-description{font-weight:500;font-size:14px}.tab_widget__info-description p{margin-bottom:1em}.tab_widget__info-description p:last-child{margin-bottom:0}.tab__widget__icon{position:unset;height:18px;width:18px}
    22
  • revenue-generator/trunk/v2/assets/build/frontend.js

    r2466307 r2468562  
    1 (()=>{"use strict";(()=>{const t=t=>{const e=t+"=",o=decodeURIComponent(document.cookie).split(";");for(let t=0;t<o.length;t++){let s=o[t];for(;" "===s.charAt(0);)s=s.substring(1);if(0===s.indexOf(e))return s.substring(e.length,s.length)}return""};class e{constructor(t){this.el=t,this.itemId=this.el.dataset.contributionId,this.closeTimeout=null,this.RESET_TIMEOUT=3e3,this.$o={form:t.querySelector(".rev-gen-contribution__form"),submitButton:t.querySelector("button[type=submit][data-mytab-button]"),amounts:t.querySelector(".rev-gen-contribution__amounts"),choose:t.querySelector(".rev-gen-contribution__choose"),customChoice:t.querySelector(".rev-gen-contribution__amount--custom"),response:t.querySelector(".rev-gen-contribution__response"),loading:t.querySelector(".rev-gen-contribution__loading"),custom:{el:t.querySelector(".rev-gen-contribution__custom"),input:t.querySelector(".rev-gen-contribution__custom input"),backButton:t.querySelector(".rev-gen-contribution-custom__back")},modal:{el:t.querySelector(".rev-gen-contribution-info-modal"),openButton:t.querySelector(".rev-gen-contribution__question-mark"),closeButton:t.querySelector(".rev-gen-contribution-info-modal__x-mark")}},this.bindEvents(),this.maybeContinueFlow()}bindEvents(){const t=this;new ResizeObserver((t=>{t.forEach((t=>{const e=t.target.dataset.breakpoints?JSON.parse(t.target.dataset.breakpoints):"";e&&Object.keys(e).forEach((o=>{const s=e[o],n="size-"+o;t.contentRect.width>=s?t.target.classList.add(n):t.target.classList.remove(n)}))}))})).observe(this.el),this.$o.customChoice.addEventListener("click",(t=>{t.preventDefault(),this.showCustomForm()})),this.$o.custom.backButton.addEventListener("click",(t=>{t.preventDefault(),this.hideCustomForm()})),this.$o.form.addEventListener("change",(()=>{this.customModeActive||(new FormData(this.$o.form).get("amount")?(this.el.classList.add("amount-selected"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.submitButton.removeAttribute("hidden")):(this.el.classList.remove("amount-selected"),this.$o.submitButton.classList.add("rev-gen-hidden"),this.$o.submitButton.addAttribute("hidden")))})),this.$o.form.addEventListener("submit",(e=>{e.preventDefault();const o=new FormData(this.$o.form),s=new XMLHttpRequest;s.open("POST",this.$o.form.getAttribute("action"),!0),s.send(o),s.onreadystatechange=function(){if(4===this.readyState){const e=JSON.parse(this.response);switch(this.status){case 200:const o=document.createElement("script");o.src=t.$o.form.dataset.tabWidgetUrl,t.$o.response.appendChild(o),t.$o.response.innerHTML=e.data.html,o.onload=()=>{t.$o.choose.classList.add("rev-gen-hidden");const e=t.el.querySelectorAll(".tab_widget__link")[1];t.setCloseTimeout(),e.addEventListener("click",(()=>{t.openInfoModal()})),t.hideSubmit()};break;case 402:t.$o.modal.openButton.classList.add("rev-gen-hidden"),t.$o.loading.classList.remove("rev-gen-hidden"),t.el.classList.add("rev-gen-contribution--payment"),t.$o.response.innerHTML=e.data.html,t.$o.choose.classList.add("rev-gen-hidden"),t.hideSubmit();break;case 401:window.location.href=e.data.auth_url}}}})),this.$o.modal.openButton.addEventListener("click",(()=>{t.openInfoModal()})),this.$o.modal.closeButton.addEventListener("click",(()=>{t.closeInfoModal()})),window.addEventListener("message",(e=>{e.data&&"OPEN_INFO_MODAL"===e.data&&t.openInfoModal()})),window.addEventListener("message",(e=>{e.data&&"PAYMENT_SUCCESSFUL"===e.data&&t.reset()})),this.el.addEventListener("rev-gen-iframe-load",(e=>{const o=e.detail||"";o&&(t.$o.loading.classList.add("rev-gen-hidden"),t.$o.modal.openButton.classList.remove("rev-gen-hidden"),o.style.height=o.contentWindow.document.body.scrollHeight+"px",t.el.classList.add("rev-gen-iframe-ready"))}))}hideSubmit(){this.$o.submitButton.classList.add("rev-gen-hidden")}showCustomForm(){this.customModeActive=!0,this.$o.amounts.classList.add("rev-gen-hidden"),this.$o.custom.el.classList.remove("rev-gen-hidden"),this.$o.custom.el.removeAttribute("hidden"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.custom.input.focus()}hideCustomForm(){this.customModeActive=!1,this.$o.form.reset(),this.$o.custom.el.classList.add("rev-gen-hidden"),this.$o.custom.el.setAttribute("hidden",""),this.$o.amounts.classList.remove("rev-gen-hidden"),this.$o.submitButton.classList.add("rev-gen-hidden")}openInfoModal(){clearTimeout(this.closeTimeout),this.$o.modal.el.classList.remove("rev-gen-hidden")}closeInfoModal(){this.$o.modal.el.classList.add("rev-gen-hidden")}reset(){this.el.classList.remove("amount-selected"),this.$o.response.innerHTML="",this.el.classList.remove("rev-gen-contribution--payment"),this.$o.form.reset(),this.$o.choose.classList.remove("rev-gen-hidden")}setCloseTimeout(){const t=this;this.closeTimeout=setTimeout((()=>{t.reset()}),t.RESET_TIMEOUT)}maybeContinueFlow(){if(!t("rgv2_data"))return;const e=JSON.parse(t("rgv2_data"));if(parseInt(this.itemId,10)!==parseInt(e.contribution.item_id,10))return;const o=this.$o.form.querySelector('[value="'+e.contribution.amount+'"]');o?o.checked=!0:(this.$o.custom.input.value=o,this.showCustomForm());const s=new MouseEvent("click");this.$o.submitButton.dispatchEvent(s)}}window.laterpayIframeLoaded=t=>{const e=t.dataset.contributionId;if(!e)return;const o=new CustomEvent("rev-gen-iframe-load",{detail:t});let s=document.querySelectorAll('.rev-gen-contribution[data-contribution-id="'+e+'"]');s=s[s.length-1],s.dispatchEvent(o)};class o{constructor(t){this.$button={trigger:t.querySelector("button"),modal:t.querySelector(".rev-gen-contribution-modal")},this.$modal={el:""},this.bindButtonEvents()}bindButtonEvents(){this.$button.trigger.addEventListener("click",this.open.bind(this))}bindModalEvents(){this.$modal.closeButton.addEventListener("click",this.close.bind(this))}open(t){t.preventDefault();const e=this.$button.modal.cloneNode(!0);this.$modal.el=e,this.$modal.contributionEl=e.querySelector(".rev-gen-contribution"),this.$modal.closeButton=e.querySelector(".rev-gen-contribution-modal__close"),document.querySelector("body").appendChild(e),this.bindModalEvents(),this.initContributionRequest(),setTimeout((function(){e.classList.add("active")}),100)}initContributionRequest(){this.contributionInstance=new e(this.$modal.contributionEl)}close(t){t.preventDefault();const e=this.$modal.el;e.classList.remove("active"),setTimeout((function(){document.querySelector("body").removeChild(e)}),200)}}document.addEventListener("DOMContentLoaded",(()=>{const t=document.getElementsByClassName("rev-gen-contribution");for(const s of t)s.dataset.type&&("button"!==s.dataset.type?new e(s):new o(s))}))})()})();
     1(()=>{"use strict";(()=>{const t=t=>{const e=t+"=",o=decodeURIComponent(document.cookie).split(";");for(let t=0;t<o.length;t++){let n=o[t];for(;" "===n.charAt(0);)n=n.substring(1);if(0===n.indexOf(e))return n.substring(e.length,n.length)}return""},e=(t,e,o)=>{const n=new Date;n.setTime(n.getTime()+24*o*60*60*1e3);const s="expires="+n.toUTCString();document.cookie=t+"="+e+";"+s+";path=/"};class o{constructor(t){this.el=t,this.itemId=this.el.dataset.contributionId,this.closeTimeout=null,this.RESET_TIMEOUT=3e3,this.$o={form:t.querySelector(".rev-gen-contribution__form"),submitButton:t.querySelector("button[type=submit][data-mytab-button]"),amounts:t.querySelector(".rev-gen-contribution__amounts"),choose:t.querySelector(".rev-gen-contribution__choose"),customChoice:t.querySelector(".rev-gen-contribution__amount--custom"),response:t.querySelector(".rev-gen-contribution__response"),loading:t.querySelector(".rev-gen-contribution__loading"),custom:{el:t.querySelector(".rev-gen-contribution__custom"),input:t.querySelector(".rev-gen-contribution__custom input"),backButton:t.querySelector(".rev-gen-contribution-custom__back")},modal:{el:t.querySelector(".rev-gen-contribution-info-modal"),openButton:t.querySelector(".rev-gen-contribution__question-mark"),closeButton:t.querySelector(".rev-gen-contribution-info-modal__x-mark")}},this.bindEvents(),this.maybeContinueFlow()}bindEvents(){const o=this;new ResizeObserver((t=>{t.forEach((t=>{const e=t.target.dataset.breakpoints?JSON.parse(t.target.dataset.breakpoints):"";e&&Object.keys(e).forEach((o=>{const n=e[o],s="size-"+o;t.contentRect.width>=n?t.target.classList.add(s):t.target.classList.remove(s)}))}))})).observe(this.el),this.$o.customChoice.addEventListener("click",(t=>{t.preventDefault(),this.showCustomForm()})),this.$o.custom.backButton.addEventListener("click",(t=>{t.preventDefault(),this.hideCustomForm()})),this.$o.form.addEventListener("change",(()=>{this.customModeActive||(new FormData(this.$o.form).get("amount")?(this.el.classList.add("amount-selected"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.submitButton.removeAttribute("hidden")):(this.el.classList.remove("amount-selected"),this.$o.submitButton.classList.add("rev-gen-hidden"),this.$o.submitButton.addAttribute("hidden")))})),this.$o.form.addEventListener("submit",(n=>{n.preventDefault();const s=new FormData(this.$o.form);s.append("rg_key",t("rg_key"));const i=new XMLHttpRequest;i.open("POST",this.$o.form.getAttribute("action"),!0),i.send(s),i.onreadystatechange=function(){if(4===this.readyState){const t=JSON.parse(this.response);switch(this.status){case 200:const n=document.createElement("script");n.src=o.$o.form.dataset.tabWidgetUrl,o.$o.response.appendChild(n),o.$o.response.innerHTML=t.data.html,n.onload=()=>{o.$o.choose.classList.add("rev-gen-hidden");const t=o.el.querySelectorAll(".tab_widget__link")[1];o.setCloseTimeout(),t.addEventListener("click",(()=>{o.openInfoModal()})),o.hideSubmit()};break;case 402:o.$o.modal.openButton.classList.add("rev-gen-hidden"),o.$o.loading.classList.remove("rev-gen-hidden"),o.el.classList.add("rev-gen-contribution--payment"),o.$o.response.innerHTML=t.data.html,o.$o.choose.classList.add("rev-gen-hidden"),o.hideSubmit();break;case 401:e("rg_key",t.data.session_key),e("rg_contribution_data",JSON.stringify(t.data.handover)),window.location.href=t.data.auth_url}}}})),this.$o.modal.openButton.addEventListener("click",(()=>{o.openInfoModal()})),this.$o.modal.closeButton.addEventListener("click",(()=>{o.closeInfoModal()})),window.addEventListener("message",(t=>{t.data&&"OPEN_INFO_MODAL"===t.data&&o.openInfoModal()})),window.addEventListener("message",(t=>{t.data&&"PAYMENT_SUCCESSFUL"===t.data&&o.reset()})),this.el.addEventListener("rev-gen-iframe-load",(t=>{const e=t.detail||"";e&&(o.$o.loading.classList.add("rev-gen-hidden"),o.$o.modal.openButton.classList.remove("rev-gen-hidden"),e.style.height=e.contentWindow.document.body.scrollHeight+"px",o.el.classList.add("rev-gen-iframe-ready"))}))}hideSubmit(){this.$o.submitButton.classList.add("rev-gen-hidden")}showCustomForm(){this.customModeActive=!0,this.$o.amounts.classList.add("rev-gen-hidden"),this.$o.custom.el.classList.remove("rev-gen-hidden"),this.$o.custom.el.removeAttribute("hidden"),this.$o.submitButton.classList.remove("rev-gen-hidden"),this.$o.custom.input.focus()}hideCustomForm(){this.customModeActive=!1,this.$o.form.reset(),this.$o.custom.el.classList.add("rev-gen-hidden"),this.$o.custom.el.setAttribute("hidden",""),this.$o.amounts.classList.remove("rev-gen-hidden"),this.$o.submitButton.classList.add("rev-gen-hidden")}openInfoModal(){clearTimeout(this.closeTimeout),this.$o.modal.el.classList.remove("rev-gen-hidden")}closeInfoModal(){this.$o.modal.el.classList.add("rev-gen-hidden")}reset(){this.el.classList.remove("amount-selected"),this.$o.response.innerHTML="",this.el.classList.remove("rev-gen-contribution--payment"),this.$o.form.reset(),this.$o.choose.classList.remove("rev-gen-hidden")}setCloseTimeout(){const t=this;this.closeTimeout=setTimeout((()=>{t.reset()}),t.RESET_TIMEOUT)}maybeContinueFlow(){if(!t("rg_contribution_data"))return;const o=JSON.parse(t("rg_contribution_data"));if(parseInt(this.itemId,10)!==parseInt(o.contribution.item_id,10))return;const n=this.$o.form.querySelector('[value="'+o.contribution.amount+'"]');n?n.checked=!0:(this.$o.custom.input.value=n,this.showCustomForm());const s=new MouseEvent("click");this.$o.submitButton.dispatchEvent(s),e("rg_contribution_data","")}}window.laterpayIframeLoaded=t=>{const e=t.dataset.contributionId;if(!e)return;const o=new CustomEvent("rev-gen-iframe-load",{detail:t});let n=document.querySelectorAll('.rev-gen-contribution[data-contribution-id="'+e+'"]');n=n[n.length-1],n.dispatchEvent(o)};class n{constructor(t){this.$button={trigger:t.querySelector("button"),modal:t.querySelector(".rev-gen-contribution-modal")},this.$modal={el:""},this.bindButtonEvents()}bindButtonEvents(){this.$button.trigger.addEventListener("click",this.open.bind(this))}bindModalEvents(){this.$modal.closeButton.addEventListener("click",this.close.bind(this))}open(t){t.preventDefault();const e=this.$button.modal.cloneNode(!0);this.$modal.el=e,this.$modal.contributionEl=e.querySelector(".rev-gen-contribution"),this.$modal.closeButton=e.querySelector(".rev-gen-contribution-modal__close"),document.querySelector("body").appendChild(e),this.bindModalEvents(),this.initContributionRequest(),setTimeout((function(){e.classList.add("active")}),100)}initContributionRequest(){this.contributionInstance=new o(this.$modal.contributionEl)}close(t){t.preventDefault();const e=this.$modal.el;e.classList.remove("active"),setTimeout((function(){document.querySelector("body").removeChild(e)}),200)}}document.addEventListener("DOMContentLoaded",(()=>{const t=document.getElementsByClassName("rev-gen-contribution");for(const e of t)e.dataset.type&&("button"!==e.dataset.type?new o(e):new n(e))}))})()})();
  • revenue-generator/trunk/v2/assets/src/js/frontend/contribution.js

    r2466307 r2468562  
    11/* global FormData, XMLHttpRequest, ResizeObserver, MouseEvent, CustomEvent */
    22
    3 import { getCookie } from '../helpers/index';
     3import { setCookie, getCookie } from '../helpers/index';
    44
    55/**
     
    134134            // Get form data.
    135135            const data = new FormData( this.$o.form );
     136            data.append( 'rg_key', getCookie( 'rg_key' ) );
    136137
    137138            // Create ajax object.
     
    145146                    const res = JSON.parse( this.response );
    146147
    147                     /* eslint-disable no-alert */
    148148                    switch ( this.status ) {
    149149                        // Item added to the tab.
     
    195195                        // User not authorized.
    196196                        case 401:
     197                            setCookie( 'rg_key', res.data.session_key );
     198                            setCookie(
     199                                'rg_contribution_data',
     200                                JSON.stringify( res.data.handover )
     201                            );
     202
    197203                            // Redirect to auth.
    198204                            window.location.href = res.data.auth_url;
    199205                            break;
    200206                    }
    201                     /* eslint-enable no-alert */
    202207                }
    203208            };
     
    326331     */
    327332    maybeContinueFlow() {
    328         if ( ! getCookie( 'rgv2_data' ) ) {
     333        if ( ! getCookie( 'rg_contribution_data' ) ) {
    329334            return;
    330335        }
    331336
    332         const clientCookie = JSON.parse( getCookie( 'rgv2_data' ) );
     337        const clientCookie = JSON.parse( getCookie( 'rg_contribution_data' ) );
    333338
    334339        if (
     
    358363        const clickEvent = new MouseEvent( 'click' );
    359364        this.$o.submitButton.dispatchEvent( clickEvent );
     365
     366        // Reset session cookie to empty value after making a contribution.
     367        setCookie( 'rg_contribution_data', '' );
    360368    }
    361369}
  • revenue-generator/trunk/v2/assets/src/js/helpers/index.js

    r2466307 r2468562  
    2525    return '';
    2626};
     27
     28export const setCookie = ( cname, cvalue, expDays ) => {
     29    const d = new Date();
     30    d.setTime( d.getTime() + expDays * 24 * 60 * 60 * 1000 );
     31    const expires = 'expires=' + d.toUTCString();
     32    document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
     33};
  • revenue-generator/trunk/v2/assets/src/scss/frontend/_component.scss

    r2466307 r2468562  
    116116}
    117117
    118 .tab_widget__link {
     118a.tab_widget__link {
    119119    @extend .font;
    120120    font-weight: 400;
     
    124124    text-decoration: underline;
    125125    cursor: pointer;
     126    &:hover,
     127    &:visited {
     128        color: $color-dark;
     129    }
    126130}
    127131
  • revenue-generator/trunk/v2/assets/src/scss/frontend/contribution-dialog.scss

    r2466307 r2468562  
    4545        height: 18px;
    4646        border-radius: 50%;
     47        font-family: $box-font;
    4748        font-weight: 700;
    4849        font-size: 12px;
     
    8182        &__title {
    8283            margin: 0;
     84            font-family: $box-font;
    8385            font-weight: 500;
    8486            font-size: 18px;
     
    9496            align-items: center;
    9597            margin: 0;
     98            font-family: $box-font;
    9699            font-weight: 500;
    97100            font-size: 14px;
     
    113116        }
    114117        &__description {
    115             font-weight: 500;
    116             font-size: 14px;
    117 
    118118            p {
    119119                margin-bottom: 1em;
     120                font-family: $box-font;
     121                font-weight: 500;
     122                font-size: 14px;
    120123                &:last-child {
    121124                    margin-bottom: 0;
     
    164167        &.amp-form-submit-success,
    165168        &.amp-form-submit-error {
     169            max-height: 250px;
     170            overflow: hidden;
    166171            margin: 0;
    167172        }
     173        div[submit-success] {
     174            position: relative;
     175            z-index: 10;
     176        }
    168177        button[type="submit"] {
     178            cursor: pointer;
    169179            max-width: 100%;
    170180            flex: 0 1 100%;
    171181            width: 100%;
    172182            padding: 15px 0;
     183            font-family: $box-font;
    173184            font-size: 15px;
    174185            border: 1px solid #000;
     
    274285        input[type="number"] {
    275286            min-width: 220px;
    276             margin-right: 5px;
     287            margin: 0 5px 0 0;
    277288            padding: 13.5px 0 13px 15px;
    278289            border-radius: 5px;
    279290            background-color: rgba(160, 160, 160, 0.12);
    280             margin-bottom: 10px;
     291            font-family: $box-font;
    281292            font-size: 14px;
    282293            outline: 0;
     
    351362        &__back {
    352363            position: relative;
    353             bottom: 5px;
     364            bottom: 0;
    354365            float: left;
    355366            cursor: pointer;
     
    640651    &__amp-show-modal {
    641652        position: absolute;
    642         bottom: 35px;
    643         left: 165px;
     653        bottom: 19px;
     654        left: 137px;
    644655        z-index: 10;
    645656        width: 95px;
  • revenue-generator/trunk/v2/inc/classes/api/class-auth-provider.php

    r2466307 r2468562  
    7474
    7575    /**
     76     * Returns a new random string to use as the state parameter in an
     77     * authorization flow.
     78     *
     79     * Adds support for PHP5 by generating state with `openssl_random_pseudo_bytes` if
     80     * `random_bytes` does not exist.
     81     *
     82     * @param  int $length Length of the random string to be generated.
     83     * @return string
     84     */
     85    protected function getRandomState( $length = 32 ) {
     86        if ( function_exists( 'random_bytes' ) ) {
     87            return bin2hex( random_bytes( $length / 2 ) );
     88        }
     89
     90        if ( function_exists( 'openssl_random_pseudo_bytes' ) ) {
     91            return bin2hex( openssl_random_pseudo_bytes( $length / 2 ) );
     92        }
     93    }
     94
     95    /**
    7696     * Check response and throw exception if error is present.
    7797     *
  • revenue-generator/trunk/v2/inc/classes/api/class-auth.php

    r2466307 r2468562  
    3838     */
    3939    const SERVER_KEY_OPTION_NAME = 'lp_rgv2_key';
    40 
    41     /**
    42      * Name of the cookie to store JWT.
    43      *
    44      * @const string
    45      */
    46     const TOKEN_COOKIE_NAME = 'rgv2_token';
    4740
    4841    /**
     
    151144
    152145    /**
    153      * Get tokens from client.
    154      *
    155      * @return boolean|JSON False on failure, JSON object on success.
    156      */
    157     private function get_jwt_from_client() {
    158         $jwt = ( isset( $_COOKIE[ self::TOKEN_COOKIE_NAME ] ) ) ? sanitize_text_field( $_COOKIE[ self::TOKEN_COOKIE_NAME ] ) : '';
    159 
    160         if ( empty( $jwt ) ) {
    161             return false;
    162         }
    163 
    164         $tokens = $this->decode_tokens( $jwt );
     146     * Get token from database if key is set.
     147     *
     148     * @return JWT
     149     */
     150    public function get_token_from_db() {
     151        $api = API::get_instance();
     152
     153        // Return false if session key is not set.
     154        if ( empty( $api->session_key ) ) {
     155            return false;
     156        }
     157
     158        // Get token by session key.
     159        $tokens = get_transient( wp_hash( $api->session_key ) );
     160        $tokens = $this->decode_tokens( $tokens, $api->session_key );
    165161
    166162        if ( is_wp_error( $tokens ) ) {
     
    174170     * Get access token.
    175171     *
    176      * This looks for a token on client first, returns false if it's not found so we can then
     172     * This looks for a token in database first, returns false if it's not found so we can then
    177173     * start the authorization code flow.
    178174     *
     
    186182        }
    187183
    188         // Get tokens from the client.
    189         $tokens = $this->get_jwt_from_client();
     184        // Get tokens from the database.
     185        $tokens = $this->get_token_from_db();
    190186
    191187        if ( ! $tokens ) {
     
    216212        }
    217213
     214        if ( ! isset( $_GET['state'] ) ) {
     215            return;
     216        }
     217
     218        $state = sanitize_text_field( $_GET['state'] );
     219
     220        $api = API::get_instance();
     221        $api->set_session( $state );
     222
    218223        $tokens = $this->get_tokens_from_provider(
    219224            'authorization_code',
    220             sanitize_text_field( $_GET['code'] )
    221         );
     225            sanitize_text_field( $_GET['code'] ),
     226            $state
     227        );
     228
     229        $client_data = $api->get_client_meta();
     230
     231        // If this is AMP, pair token to AMP client ID instead.
     232        if ( isset( $client_data['amp_id_key'] ) ) {
     233            delete_transient( wp_hash( $state ) );
     234
     235            $this->save_tokens( $tokens, $client_data['amp_id_key'] );
     236        }
    222237
    223238        $redirect_uri = site_url();
    224         $client_data  = API::get_user_cookie();
    225 
    226         if ( isset( $client_data->redirect_uri ) && ! empty( $client_data->redirect_uri ) ) {
    227             $redirect_uri = $client_data->redirect_uri;
    228         }
     239
     240        if ( isset( $client_data['redirect_uri'] ) && ! empty( $client_data['redirect_uri'] ) ) {
     241            $redirect_uri = $client_data['redirect_uri'];
     242        }
     243
     244        $api->delete_client_meta();
    229245
    230246        wp_safe_redirect( $redirect_uri );
     
    237253     * @param string $grant_type Grant type to use when obtaining a token.
    238254     * @param string $key        A key to use with the flow (auth code or refresh token).
     255     * @param string $state      OAuth state.
    239256     *
    240257     * @return AccessToken|boolean Token class instance. Boolean on failure.
    241258     */
    242     public function get_tokens_from_provider( $grant_type = 'refresh_token', $key = '' ) {
     259    public function get_tokens_from_provider( $grant_type = 'refresh_token', $key = '', $state = '' ) {
    243260        if ( empty( $key ) ) {
    244261            return false;
     
    267284            $tokens = $this->provider->getAccessToken( $grant_type, $params );
    268285
    269             $this->save_tokens( $tokens );
     286            $this->save_tokens( $tokens, $state );
    270287
    271288            return $tokens;
     
    281298     *
    282299     * @param AccessToken $tokens AccessToken instance.
     300     * @param string      $state  OAuth state.
    283301     *
    284302     * @return string Access token.
    285303     */
    286     public function save_tokens( AccessToken $tokens ) {
     304    public function save_tokens( AccessToken $tokens, $state ) {
    287305        $this->token    = $tokens->getToken();
    288         $encoded_tokens = $this->encode_tokens( $tokens );
    289 
    290         if ( isset( $_COOKIE[ self::TOKEN_COOKIE_NAME ] ) ) {
    291             unset( $_COOKIE[ self::TOKEN_COOKIE_NAME ] );
    292         }
    293 
    294         if ( ! headers_sent() ) {
    295             setcookie(
    296                 self::TOKEN_COOKIE_NAME,
    297                 $encoded_tokens,
    298                 [
    299                     'path'     => '/',
    300                     'httponly' => true,
    301                     'secure'   => is_ssl(),
    302                     'samesite' => true,
    303                     'expires'  => time() + 720 * HOUR_IN_SECONDS,
    304                 ]
    305             );
    306         }
     306        $encoded_tokens = $this->encode_tokens( $tokens, $state );
     307
     308        delete_transient( wp_hash( $state ) );
     309        set_transient( wp_hash( $state ), $encoded_tokens, 1 * MONTH_IN_SECONDS );
    307310
    308311        return $this->token;
     
    313316     *
    314317     * @param AccessToken $tokens AccessToken instance.
    315      *
    316      * @return string JWT token.
    317      */
    318     private function encode_tokens( AccessToken $tokens ) {
     318     * @param string      $key    Key to encode tokens with.
     319     *
     320     * @return mixed JWT token on success, FALSE on failure.
     321     */
     322    private function encode_tokens( AccessToken $tokens, $key = '' ) {
     323        if ( empty( $key ) ) {
     324            return false;
     325        }
     326
    319327        $payload = [
    320328            'access'  => $tokens->getToken(),
     
    323331        ];
    324332
    325         $jwt = JWT::encode( $payload, $this->key );
     333        $jwt = JWT::encode( $payload, $key );
    326334
    327335        return $jwt;
     
    332340     *
    333341     * @param string $jwt String to decode.
     342     * @param string $key Key to decode token with.
    334343     *
    335344     * @return JSON|WP_Error JSON object on success. WP_Error object on failure.
    336345     */
    337     private function decode_tokens( $jwt = '' ) {
     346    private function decode_tokens( $jwt = '', $key = '' ) {
    338347        if ( empty( $jwt ) ) {
    339348            return new \WP_Error( 'empty_jwt', 'JWT parameter cannot be empty to decode it.' );
    340349        }
    341350
     351        if ( empty( $key ) ) {
     352            return new \WP_Error( 'empty_key', 'Key needs to be provided to decode JWT token.' );
     353        }
     354
    342355        try {
    343             $decoded = JWT::decode( $jwt, $this->key, [ 'HS256' ] );
     356            $decoded = JWT::decode( $jwt, $key, [ 'HS256' ] );
    344357
    345358            return $decoded;
     
    551564     */
    552565    public function get_auth_code_url() {
    553         return $this->provider->getAuthorizationUrl();
     566        $url = $this->provider->getAuthorizationUrl();
     567
     568        return $url;
     569    }
     570
     571    /**
     572     * Get state from the authorization code flow URL.
     573     *
     574     * @param string $url URL to get the state from.
     575     *
     576     * @return string
     577     */
     578    public function get_state_from_auth_url( $url = '' ) {
     579        if ( empty( $url ) ) {
     580            return '';
     581        }
     582
     583        $parsed_url = parse_url( $url );
     584        parse_str( $parsed_url['query'], $query_params );
     585
     586        if ( ! isset( $query_params['state'] ) ) {
     587            return '';
     588        }
     589
     590        return sanitize_text_field( $query_params['state'] );
    554591    }
    555592
  • revenue-generator/trunk/v2/inc/classes/class-api.php

    r2466307 r2468562  
    3434
    3535    /**
    36      * Name of the cookie to store temporary data on client.
    37      *
    38      * @const string
    39      */
    40     const CLIENT_COOKIE_NAME = 'rgv2_data';
    41 
    42     /**
    43      * Name of the cookie with full tab ID info.
    44      *
    45      * @const string
    46      */
    47     const FULL_TAB_COOKIE_NAME = 'rgv2_full_tab_id';
    48 
    49     /**
    5036     * Auth instance.
    5137     *
     
    5339     */
    5440    public static $auth = null;
     41
     42    /**
     43     * Session key to manage meta.
     44     *
     45     * @var string
     46     */
     47    public $session_key = '';
     48
     49    /**
     50     * Hashed session key.
     51     *
     52     * @var string
     53     */
     54    private $hashed_key = '';
    5555
    5656    /**
     
    239239
    240240    /**
    241      * Get value of user cookie used when user needs to leave the site
    242      * to go through the auth process. Used to store redirect URI and amount
    243      * to contribute here.
    244      *
    245      * @return mixed Empty array on failure. JSON object on success.
    246      */
    247     public static function get_user_cookie() {
    248         $data = [];
    249 
    250         if ( ! isset( $_COOKIE[ static::CLIENT_COOKIE_NAME ] ) ) {
    251             return $data;
    252         }
    253 
    254         $data = $_COOKIE[ static::CLIENT_COOKIE_NAME ]; // phpcs:ignore -- WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    255         $data = json_decode( stripslashes( $data ) );
    256 
    257         return $data;
    258     }
    259 
    260     /**
    261      * Return user cookie parameters.
    262      *
    263      * @return array
    264      */
    265     private static function get_user_cookie_params() {
    266         return [
    267             'path'     => '/',
    268             'secure'   => is_ssl(),
    269         ];
    270     }
    271 
    272     /**
    273      * Sets data to user cookie. Unsets the cookie first if it was previously set.
    274      *
    275      * @param array $data Data to be set.
     241     * Set session key.
     242     *
     243     * @param string $session_key Session key to set.
     244     */
     245    public function set_session( $session_key = '' ) {
     246        $this->session_key = $session_key;
     247        $this->hashed_key  = wp_hash( $this->session_key );
     248    }
     249
     250    /**
     251     * Set client meta in database.
     252     *
     253     * @param string $data       Data to be stored.
     254     * @param string $type       Type of meta. Default: `meta`.
     255     * @param int    $expiration The expiration after which data will be deleted.
    276256     *
    277257     * @return void
    278258     */
    279     public static function set_user_cookie( $data = [] ) {
    280         static::unset_user_cookie();
    281 
    282         setcookie(
    283             static::CLIENT_COOKIE_NAME,
    284             json_encode( $data ),
    285             static::get_user_cookie_params()
    286         );
    287     }
    288 
    289     /**
    290      * Unsets user cookie.
    291      */
    292     public static function unset_user_cookie() {
    293         setcookie(
    294             static::CLIENT_COOKIE_NAME,
    295             '',
    296             static::get_user_cookie_params()
    297         );
    298     }
    299 
    300     /**
    301      * Sets cookie with full tab ID.
    302      *
    303      * @param string $value Tab ID.
     259    public function set_client_meta( $data = '', $type = 'meta', $expiration = 5 * MINUTE_IN_SECONDS ) {
     260        $transient_key = "{$this->hashed_key}_{$type}";
     261
     262        set_transient( $transient_key, $data, $expiration );
     263    }
     264
     265    /**
     266     * Get client meta from the database.
     267     *
     268     * @param string $type Type of meta. Default: `meta`.
     269     *
     270     * @return mixed
     271     */
     272    public function get_client_meta( $type = 'meta' ) {
     273        $transient_key = "{$this->hashed_key}_{$type}";
     274
     275        return get_transient( $transient_key );
     276    }
     277
     278    /**
     279     * Delete client meta from the database.
     280     *
     281     * @param string $type Type of meta to be deleted. Default: `meta`.
    304282     *
    305283     * @return void
    306284     */
    307     public static function set_full_tab_cookie( $value = '' ) {
    308         $params             = static::get_user_cookie_params();
    309         $params['httponly'] = true;
    310 
    311         setcookie(
    312             static::FULL_TAB_COOKIE_NAME,
    313             $value,
    314             $params
    315         );
    316     }
    317 
    318     /**
    319      * Get value of full tab cookie.
    320      *
    321      * @return string
    322      */
    323     public static function get_full_tab_cookie() {
    324         $value = '';
    325 
    326         if ( ! isset( $_COOKIE[ static::FULL_TAB_COOKIE_NAME ] ) ) {
    327             return $value;
    328         }
    329 
    330         $value = sanitize_text_field( $_COOKIE[ static::FULL_TAB_COOKIE_NAME ] );
    331 
    332         return $value;
    333     }
    334 
    335     /**
    336      * Unsets cookie with full tab ID.
    337      */
    338     public static function unset_full_tab_cookie() {
    339         static::set_full_tab_cookie( '' );
     285    public function delete_client_meta( $type = 'meta' ) {
     286        $transient_key = "{$this->hashed_key}_{$type}";
     287
     288        delete_transient( $transient_key );
    340289    }
    341290
  • revenue-generator/trunk/v2/inc/classes/class-frontend-post.php

    r2466307 r2468562  
    3636     * @const string
    3737     */
    38     const TAB_WIDGET_SCRIPT_URL = 'https://assets.sbx.laterpay.net/pcpro-jsx-components-frontend/main.js';
     38    const TAB_WIDGET_SCRIPT_URL = 'https://assets.laterpay.net/pcpro-jsx-components-frontend/main.js';
    3939
    4040    /**
     
    7272     */
    7373    const MYTAB_SBX_URL = 'https://mytab.sbx.laterpay.net';
    74 
    75     /**
    76      * Tab data cookie name for AMP context.
    77      *
    78      * @const string
    79      */
    80     const AMP_TAB_DATA_COOKIE_NAME = 'amp_lp_tab_data';
    8174
    8275    /**
     
    131124        add_action( 'parse_request', [ $this, 'handle_payment_iframe_redirect' ] );
    132125        add_action( 'parse_request', [ $this, 'handle_purchase_iframe_display' ] );
     126        add_action( 'parse_request', [ $this, 'handle_json_amp_url' ] );
     127        add_action( 'wp_print_footer_scripts', [ $this, 'print_amp_script' ] );
     128        add_action( 'wp_head', [ $this, 'add_amp_script_hash' ] );
    133129    }
    134130
     
    187183        $is_amp        = ( isset( $_REQUEST['is_amp'] ) && 1 === (int) $_REQUEST['is_amp'] );
    188184        $layout_type   = ( isset( $_REQUEST['layout_type'] ) ) ? sanitize_text_field( $_REQUEST['layout_type'] ) : '';
     185        $key           = ( isset( $_REQUEST['rg_key'] ) ) ? sanitize_text_field( $_REQUEST['rg_key'] ) : '';
    189186        $redirect_uri  = ( isset( $_REQUEST['redirect_uri'] ) ) ? esc_url( $_REQUEST['redirect_uri'] ) : ''; // phpcs:ignore -- WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    190187
     
    210207        $api = API::get_instance();
    211208
     209        // If session key is present, set it to API instance.
     210        if ( ! empty( $key ) ) {
     211            $api->set_session( $key );
     212        }
     213
    212214        /**
    213215         * If user is not authorized, return auth flow URL for them in the response
     
    215217         */
    216218        if ( ! $api->is_user_authorized() ) {
    217             /**
    218              * Set data to store in the cookie so we can redirect user and
    219              * continue their flow.
    220              */
     219            // Reset session if in AMP context as we want to pair data to AMP client ID instead.
     220            if ( $is_amp ) {
     221                $api->set_session( '' );
     222
     223                $amp_id_key = '';
     224
     225                if ( $is_amp ) {
     226                    $amp_id_key = $key;
     227                }
     228            }
     229
     230            $auth_url = $api::$auth->get_auth_code_url();
     231            $state    = $api::$auth->get_state_from_auth_url( $auth_url );
     232
     233            $api->set_session( $state );
     234
     235            $redirect_uri = $redirect_uri;
     236
     237            // Set specific AMP redirect URI to redirect back to AMP context.
     238            if ( $is_amp ) {
     239                $redirect_uri = add_query_arg(
     240                    [
     241                        'amp'     => 1,
     242                        'session' => $state,
     243                    ],
     244                    $redirect_uri
     245                );
     246            }
     247
    221248            $client_data = [
    222249                'redirect_uri' => $redirect_uri,
    223                 'contribution' => [
    224                     'amount'  => number_format( $amount, 2 ),
    225                     'item_id' => $item_id,
    226                 ],
    227250            ];
    228251
    229             // Store data to a cookie.
    230             API::set_user_cookie( $client_data );
     252            // Add reference to AMP client ID to client meta for future linking.
     253            if ( $is_amp ) {
     254                $client_data['amp_id_key'] = $amp_id_key;
     255            }
     256
     257            $api->set_client_meta( $client_data );
     258
     259            if ( $is_amp ) {
     260                header( 'AMP-Redirect-To: ' . $auth_url );
     261                header( 'Access-Control-Expose-Headers: AMP-Redirect-To' );
     262            }
    231263
    232264            // Send JSON response with auth code flow URL and 401 code.
     
    234266                [
    235267                    'data' => [
    236                         'auth_url' => $api::$auth->get_auth_code_url(),
     268                        'auth_url'    => $auth_url,
     269                        'session_key' => $api->session_key,
     270                        'handover'    => [
     271                            'contribution' => [
     272                                'amount'  => number_format( $amount, 2 ),
     273                                'item_id' => $item_id,
     274                            ],
     275                        ],
    237276                    ],
    238277                ],
     
    277316
    278317            if ( $is_amp ) {
    279                 setcookie(
    280                     static::AMP_TAB_DATA_COOKIE_NAME,
    281                     json_encode( $tab_data ),
    282                     [
    283                         'path'   => '/',
    284                         'secure' => is_ssl(),
    285                     ]
    286                 );
     318                $api->set_client_meta( $tab_data, 'amp_payment' );
    287319            }
    288320
     
    310342                );
    311343
    312                 API::unset_user_cookie();
    313 
    314344                wp_send_json(
    315345                    $response,
     
    325355             */
    326356            case 402:
    327                 $credentials = $api::$auth->get_credentials();
    328 
    329                 // Set cookie with full tab ID to use when redirecting.
    330                 $api::set_full_tab_cookie( $response['data']['tab']['id'] );
    331 
    332357                $iframe_url = static::get_payment_iframe_url();
    333 
    334358                $iframe_url = add_query_arg(
    335359                    [
    336                         'layout_type' => $layout_type,
     360                        'key' => $key,
     361                        'v'   => time(),
    337362                    ],
    338363                    $iframe_url
    339364                );
     365
     366                $meta = [
     367                    'tab_id'      => $tab_data['id'],
     368                    'layout_type' => $layout_type,
     369                ];
     370
     371                // Store full tab ID and layout type in payment meta.
     372                $api->set_client_meta( $meta, 'payment' );
    340373
    341374                $response['data']['payment_required'] = true;
     
    347380                );
    348381
    349                 API::unset_user_cookie();
    350 
    351382                wp_send_json(
    352383                    $response,
     
    413444
    414445    /**
    415      * Get iframe URL for purchase component display (AMP).
    416      *
    417      * @return string
    418      */
    419     public static function get_purchase_iframe_url() {
    420         $url = site_url();
    421         $url = add_query_arg( 'laterpay', 'purchase', $url );
    422 
    423         return $url;
    424     }
    425 
    426     /**
    427446     * Intercept request. When `?laterpay` is present and set to `payment`,
    428447     * make a call to payment component and render it before WP theme initializes.
     
    439458        }
    440459
    441         $layout_type = '';
    442 
    443         if ( isset( $_GET['layout_type'] ) ) {
    444             $layout_type = sanitize_text_field( $_GET['layout_type'] );
    445         }
    446 
    447         $api    = API::get_instance();
    448         $tab_id = $api::get_full_tab_cookie();
     460        if ( ! isset( $_GET['key'] ) ) {
     461            return;
     462        }
     463
     464        $key = sanitize_text_field( $_GET['key'] );
     465
     466        if ( empty( $key ) ) {
     467            return;
     468        }
     469
     470        $api = API::get_instance();
     471        $api->set_session( $key );
     472
     473        // Get full tab ID and layout type previously set to client meta.
     474        $payment_data = $api->get_client_meta( 'payment' );
    449475
    450476        $req = wp_remote_get(
     
    453479                'headers' => [
    454480                    'x-lp-access-token'  => $api::$auth->get_access_token(),
    455                     'x-lp-tab-id'        => $tab_id,
    456                     'x-lp-amp'           => ( function_exists( 'is_amp' ) && is_amp() ),
    457                     'x-lp-theme'         => $layout_type,
     481                    'x-lp-tab-id'        => $payment_data['tab_id'],
     482                    'x-lp-amp'           => ( isset( $_GET['amp'] ) ),
     483                    'x-lp-theme'         => $payment_data['layout_type'],
    458484                ],
    459485            ]
     
    462488        $res = wp_remote_retrieve_body( $req );
    463489
     490        header( 'Access-Control-Allow-Origin: ' . site_url() );
    464491        header( 'Content-Type: text/html; charset=UTF-8' );
    465492
    466493        echo $res; // phpcs:ignore -- WordPress.Security.EscapeOutput.OutputNotEscaped
     494
     495        // Clean up. Delete client meta and payment meta.
     496        $api->delete_client_meta();
     497        $api->delete_client_meta( 'payment' );
    467498
    468499        exit();
     
    482513            return;
    483514        }
     515
     516        if ( ! isset( $_GET['key'] ) ) {
     517            return;
     518        }
     519
     520        $key = sanitize_text_field( $_GET['key'] );
     521
     522        $api = API::get_instance();
     523        $api->set_session( $key );
     524
     525        $amp_meta = $api->get_client_meta( 'amp_payment' );
    484526
    485527        $api      = API::get_instance();
     
    491533        ];
    492534
    493         if ( isset( $_COOKIE[ static::AMP_TAB_DATA_COOKIE_NAME ] ) ) {
    494             $tab_data = wp_parse_args(
    495                 json_decode(
    496                     stripslashes( $_COOKIE[ static::AMP_TAB_DATA_COOKIE_NAME ] ) // phpcs:ignore -- WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    497                 ),
    498                 $tab_data
    499             );
    500         }
     535        $tab_data = wp_parse_args( $amp_meta, $tab_data );
    501536
    502537        // Data to use in the template.
     
    515550    }
    516551
     552    /**
     553     * Outputs simple URL where we'll listen to and intercept the request
     554     * to render a JSON.
     555     *
     556     * @param string $type Type of the JSON to echo.
     557     *
     558     * @return string
     559     */
     560    public static function get_json_amp_url( $type = '' ) {
     561        if ( empty( $type ) ) {
     562            return;
     563        }
     564
     565        $url = add_query_arg(
     566            [
     567                'laterpay' => 'json',
     568                'type'     => $type,
     569            ],
     570            site_url()
     571        );
     572
     573        return $url;
     574    }
     575
     576    /**
     577     * Intercept the request and output JSON with the URL to either purchase
     578     * or payment component for AMP purposes.
     579     *
     580     * AMP implementation uses `<amp-list>` to grab values of this JSON and
     581     * then dynamically renders `<iframe>` with `src` coming from this JSON.
     582     * This allows us to render iframe with the URL queries we need and
     583     * overcome the limitation of `<amp-iframe>` alone which does not allow
     584     * for dynamic attributes by default.
     585     *
     586     * @return string
     587     */
     588    public function handle_json_amp_url() {
     589        if ( ! isset( $_GET['laterpay'] ) ) {
     590            return;
     591        }
     592
     593        if ( 'json' !== sanitize_text_field( $_GET['laterpay'] ) ) {
     594            return;
     595        }
     596
     597        if ( ! isset( $_GET['type'] ) ) {
     598            return;
     599        }
     600
     601        if ( ! isset( $_GET['key'] ) ) {
     602            return;
     603        }
     604
     605        $type = sanitize_text_field( $_GET['type'] );
     606        $key  = sanitize_text_field( $_GET['key'] );
     607
     608        header( 'Content-type: application/json' );
     609
     610        $url = self::get_payment_iframe_url();
     611
     612        $url = add_query_arg(
     613            [
     614                'key' => $key,
     615                'amp' => 1,
     616            ],
     617            $url
     618        );
     619
     620        $json = json_encode(
     621            [
     622                'items' => [
     623                    [
     624                        'url' => $url,
     625                    ],
     626                ],
     627            ]
     628        );
     629
     630        echo $json; // phpcs:ignore -- WordPress.Security.EscapeOutput.OutputNotEscaped -- output is formed in this method so no need to further escape
     631
     632        exit();
     633    }
     634
     635    /**
     636     * Print AMP purchase component script if in AMP context.
     637     *
     638     * @hooked action `wp_print_footer_scripts`
     639     */
     640    public function print_amp_script() {
     641        if ( ! function_exists( 'is_amp_endpoint' ) || ! is_amp_endpoint() ) {
     642            return;
     643        }
     644
     645        include REVENUE_GENERATOR_PLUGIN_DIR . '/v2/templates/frontend/contribution/amp-purchase-component.php';
     646    }
     647
     648    /**
     649     * Print AMP purchase component script hash to wp_head if
     650     * in AMP context.
     651     *
     652     * @hooked action `wp_head`
     653     */
     654    public function add_amp_script_hash() {
     655        if ( ! function_exists( 'is_amp_endpoint' ) || ! is_amp_endpoint() ) {
     656            return;
     657        }
     658        ?>
     659        <meta name="amp-script-src" content="sha384-Xcsn0uFdGgT5Rk2GgmeML-rKQU6kfiRtPfrouuTo0sjizpodOzkcwzV8uBn2zyo9">
     660        <?php
     661    }
     662
    517663}
  • revenue-generator/trunk/v2/templates/frontend/contribution/partial-amounts.php

    r2466307 r2468562  
    1313global $wp;
    1414?>
     15
     16<?php
     17/**
     18 * The following bit is added so that AMP compiled CSS include
     19 * the purchase component styles which is not yet available
     20 * in DOM at the time of render.
     21 */
     22?>
     23<?php if ( $is_amp ) : ?>
     24    <div class="tab_widget__container tab_widget__arc-container tab_widget__arc--background tab_widget__arc--filled tab_widget__donated-amount-text tab_widget__thank-you-message tab_widget__links-container tab_widget__link tab_widget__links-separator tab_widget__container-hidden tab_widget__container-visible tab_widget__regular-text tab_widget tab_widget__arc-animation lp__root lp__tab-widget-data tab__widget__info-button__container tab__widget__info-button tab__widget__info-button-question-mark tab__widget__close-button-x-mark tab_widget__container__info-screen infoContainer title steps step stepText stepNumber description tab__widget__icon" style="display: none;"></div>
     25<?php endif; ?>
     26
    1527<div class="rev-gen-contribution__donate" id="<?php echo esc_attr( $html_id ); ?>_donate">
    1628    <form class="rev-gen-contribution__form" action="<?php echo esc_url( admin_url() ); ?>admin-ajax.php" method="POST" id="<?php echo esc_attr( $html_id ); ?>_donate-form" action-xhr="<?php echo esc_url( admin_url() ); ?>admin-ajax.php" data-tab-widget-url="<?php echo esc_url( Frontend_Post::get_tab_widget_script_url() ); ?>" on="submit:AMP.setState({ submitted: 1, submitting: 1 })">
     
    1830        <div submit-success>
    1931            <span on="tap:<?php echo esc_attr( $html_id ); ?>_info-modal.show" class="rev-gen-contribution__amp-show-modal"></span>
    20             <iframe src="<?php echo esc_url( Frontend_Post::get_purchase_iframe_url() ); ?>" height="105"></iframe>
     32            <template type="amp-mustache">
     33                <amp-script layout="fixed" height="105" width="330" script="revenue-generator-amp-purchase-component">
     34                    <div class="lp__root">
     35                        <div class="lp__tab-widget-data"
     36                        data-tab-amount="{{ data.tab.total }}"
     37                        data-tab-currency="USD"
     38                        data-tab-limit="{{ data.tab.limit }}"
     39                        data-view-tab-url="https://mytab.laterpay.net"></div>
     40                    </div>
     41                </amp-script>
     42            </template>
    2143        </div>
    2244        <div submit-error>
    2345            <span on="tap:<?php echo esc_attr( $html_id ); ?>_info-modal.show" class="rev-gen-contribution__amp-show-modal--purchase"></span>
    24             <iframe src="<?php echo esc_url( Frontend_Post::get_payment_iframe_url() ); ?>" height="250"></iframe>
     46            <amp-list width="auto" height="250" src="<?php echo esc_url( Frontend_Post::get_json_amp_url( 'payment' ) ); ?>&key=CLIENT_ID(uid)" max-items="1">
     47                <template type="amp-mustache">
     48                    <iframe src="{{url}}" sandbox="allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation-by-user-activation" width="100%" height="250" allowpaymentrequest></iframe>
     49                </template>
     50            </amp-list>
    2551        </div>
    2652        <?php endif; ?>
     
    3157        <input type="hidden" name="action" value="<?php echo esc_attr( Frontend_Post::CONTRIBUTION_AJAX_ACTION ); ?>">
    3258        <?php if ( $is_amp ) : ?>
     59        <input type="hidden" name="rg_key" value="CLIENT_ID(uid)" data-amp-replace="CLIENT_ID">
    3360        <input type="hidden" name="is_amp" value="1">
    3461        <?php endif; ?>
  • revenue-generator/trunk/vendor/autoload.php

    r2466307 r2468562  
    55require_once __DIR__ . '/composer/autoload_real.php';
    66
    7 return ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b::getLoader();
     7return ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045::getLoader();
  • revenue-generator/trunk/vendor/composer/InstalledVersions.php

    r2466307 r2468562  
    2525  'root' =>
    2626  array (
    27     'pretty_version' => '2.0.0',
    28     'version' => '2.0.0.0',
     27    'pretty_version' => '2.0.1',
     28    'version' => '2.0.1.0',
    2929    'aliases' =>
    3030    array (
     
    7373    'laterpay/revenue-generator' =>
    7474    array (
    75       'pretty_version' => '2.0.0',
    76       'version' => '2.0.0.0',
     75      'pretty_version' => '2.0.1',
     76      'version' => '2.0.1.0',
    7777      'aliases' =>
    7878      array (
  • revenue-generator/trunk/vendor/composer/autoload_real.php

    r2466307 r2468562  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b
     5class ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
    29         spl_autoload_unregister(array('ComposerAutoloaderInit1f8be73ed8b3d6b4c601375036a77c9b', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit0180107ac78f1fe5f7e96ac594582045', 'loadClassLoader'));
    3030
    3131        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
     
    3333            require __DIR__ . '/autoload_static.php';
    3434
    35             call_user_func(\Composer\Autoload\ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::getInitializer($loader));
     35            call_user_func(\Composer\Autoload\ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::getInitializer($loader));
    3636        } else {
    3737            $map = require __DIR__ . '/autoload_namespaces.php';
     
    5454
    5555        if ($useStaticLoader) {
    56             $includeFiles = Composer\Autoload\ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$files;
     56            $includeFiles = Composer\Autoload\ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$files;
    5757        } else {
    5858            $includeFiles = require __DIR__ . '/autoload_files.php';
    5959        }
    6060        foreach ($includeFiles as $fileIdentifier => $file) {
    61             composerRequire1f8be73ed8b3d6b4c601375036a77c9b($fileIdentifier, $file);
     61            composerRequire0180107ac78f1fe5f7e96ac594582045($fileIdentifier, $file);
    6262        }
    6363
     
    6666}
    6767
    68 function composerRequire1f8be73ed8b3d6b4c601375036a77c9b($fileIdentifier, $file)
     68function composerRequire0180107ac78f1fe5f7e96ac594582045($fileIdentifier, $file)
    6969{
    7070    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  • revenue-generator/trunk/vendor/composer/autoload_static.php

    r2466307 r2468562  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b
     7class ComposerStaticInit0180107ac78f1fe5f7e96ac594582045
    88{
    99    public static $files = array (
     
    198198    {
    199199        return \Closure::bind(function () use ($loader) {
    200             $loader->prefixLengthsPsr4 = ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$prefixLengthsPsr4;
    201             $loader->prefixDirsPsr4 = ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$prefixDirsPsr4;
    202             $loader->classMap = ComposerStaticInit1f8be73ed8b3d6b4c601375036a77c9b::$classMap;
     200            $loader->prefixLengthsPsr4 = ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$prefixLengthsPsr4;
     201            $loader->prefixDirsPsr4 = ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$prefixDirsPsr4;
     202            $loader->classMap = ComposerStaticInit0180107ac78f1fe5f7e96ac594582045::$classMap;
    203203
    204204        }, null, ClassLoader::class);
  • revenue-generator/trunk/vendor/composer/installed.php

    r2466307 r2468562  
    22  'root' =>
    33  array (
    4     'pretty_version' => '2.0.0',
    5     'version' => '2.0.0.0',
     4    'pretty_version' => '2.0.1',
     5    'version' => '2.0.1.0',
    66    'aliases' =>
    77    array (
     
    5050    'laterpay/revenue-generator' =>
    5151    array (
    52       'pretty_version' => '2.0.0',
    53       'version' => '2.0.0.0',
     52      'pretty_version' => '2.0.1',
     53      'version' => '2.0.1.0',
    5454      'aliases' =>
    5555      array (
Note: See TracChangeset for help on using the changeset viewer.