diff --git a/third_party/subscriptions-project/config.js b/third_party/subscriptions-project/config.js index 93f919c3e03a..b774617c268d 100644 --- a/third_party/subscriptions-project/config.js +++ b/third_party/subscriptions-project/config.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** Version: 0.1.22.161 */ +/** Version: 0.1.22.163 */ /** * Copyright 2018 The Subscribe with Google Authors. All Rights Reserved. * diff --git a/third_party/subscriptions-project/swg-button.css b/third_party/subscriptions-project/swg-button.css index fc79c918048b..a064fb5744f8 100644 --- a/third_party/subscriptions-project/swg-button.css +++ b/third_party/subscriptions-project/swg-button.css @@ -288,17 +288,36 @@ min-height: 44px; display: inline-flex; align-items: center; - box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); box-sizing: border-box; font-family: 'Google Sans', 'Roboto-Regular', sans-serif, arial; font-weight: 500; font-size: 14px; letter-spacing: .001em; + cursor: pointer; } .swg-button-v2-light { color: #1A73E8; background-color: #fff; + border: 1px solid #DADCE0; +} + +.swg-button-v2-light:hover { + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); + background: linear-gradient(0deg, rgba(26, 115, 232, 0.04), rgba(26, 115, 232, 0.04)), #FFFFFF; + border: none; +} + +.swg-button-v2-light:focus { + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 2px 6px 2px rgba(60, 64, 67, 0.15); + background: linear-gradient(0deg, rgba(26, 115, 232, 0.08), rgba(26, 115, 232, 0.08)), #FFFFFF; + border: none; +} + +.swg-button-v2-light:active { + background-color: #fff; + box-shadow: 0px 6px 10px 4px rgba(60, 64, 67, 0.15), 0px 2px 3px rgba(60, 64, 67, 0.3); + border: none; } .swg-button-v2-dark { @@ -306,6 +325,14 @@ background-color: #3C4043; } +.swg-button-v2-dark:hover, .swg-button-v2-dark:active { + box-shadow: 0px 2px 6px 2px rgba(0, 0, 0, 0.15), 0px 1px 2px rgba(0, 0, 0, 0.3); +} + +.swg-button-v2-dark:focus { + box-shadow: 0px 6px 10px 4px rgba(0, 0, 0, 0.15), 0px 2px 3px rgba(0, 0, 0, 0.3); +} + .swg-button-v2-icon-light, .swg-button-v2-icon-dark { width: 18px; diff --git a/third_party/subscriptions-project/swg-gaa.js b/third_party/subscriptions-project/swg-gaa.js index 43a55592cb9b..5e876571cdb7 100644 --- a/third_party/subscriptions-project/swg-gaa.js +++ b/third_party/subscriptions-project/swg-gaa.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** Version: 0.1.22.161 */ +/** Version: 0.1.22.163 */ /** * Copyright 2018 The Subscribe with Google Authors. All Rights Reserved. * @@ -35,13 +35,17 @@ const I18N_STRINGS = { 'SHOWCASE_REGWALL_TITLE': { + 'cs': 'Získejte s Googlem víc', 'de': 'Immer gut informiert mit Google', 'en': 'Get more with Google', 'es-ar': 'Disfruta más artículos con Google', 'fr': 'Plus de contenus avec Google', + 'it': 'Con Google puoi avere di più', 'pt-br': 'Veja mais com o Google', }, 'SHOWCASE_REGWALL_DESCRIPTION': { + 'cs': + 'Tento obsah je obvykle zpoplatněn, ale pokud se do publikace AP News{publication} zaregistrujete pomocí účtu Google, získáte od Googlu přístup zdarma.', 'de': 'Dieser Inhalt ist normalerweise kostenpflichtig. Google gewährt dir jedoch kostenlos Zugriff auf diesen Artikel und andere Inhalte, wenn du dich mit deinem Google-Konto bei AP News{publication} registrierst.', 'en': @@ -50,21 +54,27 @@ const I18N_STRINGS = { 'Normalmente, es necesario pagar para ver este contenido, pero Google te ofrece acceso gratuito a este y otros artículos si te registras en AP News{publication} con tu Cuenta de Google.', 'fr': 'Ce contenu est généralement payant, mais vous pouvez lire cet article et d\'autres contenus gratuitement grâce à Google en vous inscrivant sur AP News{publication} avec votre compte Google.', + 'it': + 'Generalmente questi contenuti sono a pagamento, ma Google ti offre accesso gratuito a questo articolo e ad altri articoli se ti registri a AP News{publication} usando il tuo Account Google.', 'pt-br': 'Normalmente, é preciso pagar por este conteúdo. Porém, basta você se registrar na publicação AP News{publication} usando sua Conta do Google para ter acesso gratuito a esta matéria e muito mais.', }, 'SHOWCASE_REGWALL_PUBLISHER_SIGN_IN_BUTTON': { + 'cs': 'Už máte účet?', 'de': 'Du hast bereits ein Konto?', 'en': 'Already have an account?', 'es-ar': '¿Ya tienes una cuenta?', 'fr': 'Vous avez déjà un compte ?', + 'it': 'Hai già un account?', 'pt-br': 'Já tem uma conta?', }, 'SHOWCASE_REGWALL_GOOGLE_SIGN_IN_BUTTON': { + 'cs': 'Přihlásit se přes Google', 'de': 'Über Google anmelden', 'en': 'Sign in with Google', 'es-ar': 'Acceder con Google', 'fr': 'Se connecter avec Google', + 'it': 'Accedi con Google', 'pt-br': 'Fazer login com o Google', }, }; diff --git a/third_party/subscriptions-project/swg.js b/third_party/subscriptions-project/swg.js index 8673b90e6179..31399c54f2e1 100644 --- a/third_party/subscriptions-project/swg.js +++ b/third_party/subscriptions-project/swg.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** Version: 0.1.22.161 */ +/** Version: 0.1.22.163 */ /** * Copyright 2018 The Subscribe with Google Authors. All Rights Reserved. * @@ -57,6 +57,7 @@ const AnalyticsEvent = { IMPRESSION_SHOWCASE_REGWALL: 23, IMPRESSION_SWG_SUBSCRIPTION_MINI_PROMPT: 24, IMPRESSION_SWG_CONTRIBUTION_MINI_PROMPT: 25, + IMPRESSION_CONTRIBUTION_OFFERS: 26, ACTION_SUBSCRIBE: 1000, ACTION_PAYMENT_COMPLETE: 1001, ACTION_ACCOUNT_CREATED: 1002, @@ -91,6 +92,7 @@ const AnalyticsEvent = { ACTION_SWG_CONTRIBUTION_MINI_PROMPT_CLICK: 1031, ACTION_SWG_SUBSCRIPTION_MINI_PROMPT_CLOSE: 1032, ACTION_SWG_CONTRIBUTION_MINI_PROMPT_CLOSE: 1033, + ACTION_CONTRIBUTION_OFFER_SELECTED: 1034, EVENT_PAYMENT_FAILED: 2000, EVENT_CUSTOM: 3000, EVENT_CONFIRM_TX_ID: 3001, @@ -4471,9 +4473,10 @@ function adsUrl(url) { /** * @param {string} url Relative URL, e.g. "/offersiframe". * @param {string=} prefix + * @param {Object=} params List of extra params to append to the URL. * @return {string} The complete URL. */ -function feUrl(url, prefix = '') { +function feUrl(url, prefix = '', params) { // Add cache param. url = feCached('https://news.google.com' + prefix + '/swg/_/ui/v1' + url); @@ -4484,6 +4487,10 @@ function feUrl(url, prefix = '') { url = addQueryParam(url, 'jsmode', boqJsMode); } + for (const param in params) { + url = addQueryParam(url, param, params[param]); + } + return url; } @@ -4501,7 +4508,7 @@ function feCached(url) { */ function feArgs(args) { return Object.assign(args, { - '_client': 'SwG 0.1.22.161', + '_client': 'SwG 0.1.22.163', }); } @@ -4687,6 +4694,8 @@ class PayStartFlow { { forceRedirect: this.deps_.config().windowOpenMode == WindowOpenMode.REDIRECT, + // basic flow does not support native. + forceDisableNative: paySwgVersion == '2', } ); return Promise.resolve(); @@ -5284,10 +5293,6 @@ class OffersFlow { ViewSubscriptionsResponse, this.startNativeFlow_.bind(this) ); - activityIframeView.on( - EntitlementsResponse, - this.handleEntitlementsResponse_.bind(this) - ); return this.dialogManager_.openView(activityIframeView); }); @@ -5718,7 +5723,7 @@ class ActivityPorts$1 { 'analyticsContext': context.toArray(), 'publicationId': pageConfig.getPublicationId(), 'productId': pageConfig.getProductId(), - '_client': 'SwG 0.1.22.161', + '_client': 'SwG 0.1.22.163', 'supportsEventManager': true, }, args || {} @@ -6566,7 +6571,7 @@ class AnalyticsService { context.setTransactionId(getUuid()); } context.setReferringOrigin(parseUrl(this.getReferrer_()).origin); - context.setClientVersion('SwG 0.1.22.161'); + context.setClientVersion('SwG 0.1.22.163'); context.setUrl(getCanonicalUrl(this.doc_)); const utmParams = parseQueryString(this.getQueryString_()); @@ -9867,14 +9872,9 @@ class Toast { animate_(callback) { const wait = this.animating_ || Promise.resolve(); return (this.animating_ = wait - .then( - () => { - return callback(); - }, - () => { - // Ignore errors to make sure animations don't get stuck. - } - ) + .then(() => callback()) + // Ignore errors to make sure animations don't get stuck. + .catch(() => {}) .then(() => { this.animating_ = null; })); @@ -10005,6 +10005,92 @@ const AnalyticsEventToEntitlementResult = { [AnalyticsEvent.IMPRESSION_PAYWALL]: EntitlementResult.LOCKED_PAYWALL, }; +/** + * @param {!string} eventCategory + * @param {!string} eventAction + * @param {!string} eventLabel + * @param {!boolean} nonInteraction + * @returns {!Object} + */ +const createGoogleAnalyticsEvent = ( + eventCategory, + eventAction, + eventLabel, + nonInteraction +) => ({ + eventCategory, + eventAction, + eventLabel, + nonInteraction, +}); + +/** @const {!Object} */ +const AnalyticsEventToGoogleAnalyticsEvent = { + [AnalyticsEvent.IMPRESSION_OFFERS]: createGoogleAnalyticsEvent( + 'NTG paywall', + 'paywall modal impression', + '', + true + ), + [AnalyticsEvent.IMPRESSION_CONTRIBUTION_OFFERS]: createGoogleAnalyticsEvent( + 'NTG membership', + 'offer impressions', + '', + true + ), + + [AnalyticsEvent.ACTION_OFFER_SELECTED]: createGoogleAnalyticsEvent( + 'NTG paywall', + 'click', + '', + false + ), + [AnalyticsEvent.ACTION_SWG_SUBSCRIPTION_MINI_PROMPT_CLICK]: createGoogleAnalyticsEvent( + 'NTG subscription', + 'marketing modal click', + '', + false + ), + [AnalyticsEvent.IMPRESSION_SWG_SUBSCRIPTION_MINI_PROMPT]: createGoogleAnalyticsEvent( + 'NTG subscription', + 'marketing modal impression', + '', + true + ), + [AnalyticsEvent.ACTION_SWG_CONTRIBUTION_MINI_PROMPT_CLICK]: createGoogleAnalyticsEvent( + 'NTG membership', + 'marketing modal click', + '', + false + ), + [AnalyticsEvent.IMPRESSION_SWG_CONTRIBUTION_MINI_PROMPT]: createGoogleAnalyticsEvent( + 'NTG membership', + 'membership modal impression', + '', + true + ), +}; + +/** @const {!Object} */ +const SubscriptionSpecificAnalyticsEventToGoogleAnalyticsEvent = { + [AnalyticsEvent.ACTION_PAYMENT_COMPLETE]: createGoogleAnalyticsEvent( + 'NTG subscription', + 'submit', + 'success', + false + ), +}; + +/** @const {!Object} */ +const ContributionSpecificAnalyticsEventToGoogleAnalyticsEvent = { + [AnalyticsEvent.ACTION_PAYMENT_COMPLETE]: createGoogleAnalyticsEvent( + 'NTG membership', + 'submit', + 'success', + false + ), +}; + /** * Converts a propensity event enum into an analytics event enum. * @param {!Event|string} propensityEvent @@ -10036,6 +10122,24 @@ function analyticsEventToEntitlementResult(event) { return AnalyticsEventToEntitlementResult[event]; } +/** + * Converts an analytics event enum into a Google Analytics event object. + * @param {?AnalyticsEvent} event + * @param {string} subscriptionFlow + * @returns {?Object} + */ +function analyticsEventToGoogleAnalyticsEvent(event, subscriptionFlow) { + let gaEvent = null; + if (subscriptionFlow) { + if (subscriptionFlow == SubscriptionFlows.SUBSCRIBE) { + gaEvent = SubscriptionSpecificAnalyticsEventToGoogleAnalyticsEvent[event]; + } else if (subscriptionFlow == SubscriptionFlows.CONTRIBUTE) { + gaEvent = ContributionSpecificAnalyticsEventToGoogleAnalyticsEvent[event]; + } + } + return gaEvent || AnalyticsEventToGoogleAnalyticsEvent[event]; +} + /** * Copyright 2020 The Subscribe with Google Authors. All Rights Reserved. * @@ -11146,24 +11250,6 @@ class FetchResponse { )); } - /** - * Reads the xhr responseXML. - * @return {!Promise} - * @private - */ - document_() { - assert(!this.bodyUsed, 'Body already used'); - this.bodyUsed = true; - assert( - this.xhr_.responseXML, - 'responseXML should exist. Make sure to return ' + - 'Content-Type: text/html header.' - ); - return /** @type {!Promise} */ (Promise.resolve( - assert(this.xhr_.responseXML) - )); - } - /** * Drains the response and returns a promise that resolves with the response * ArrayBuffer. @@ -11319,6 +11405,62 @@ class XhrFetcher { } } +/** + * Copyright 2021 The Subscribe with Google Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class GoogleAnalyticsEventListener { + /** + * @param {!./deps.DepsDef} deps + */ + constructor(deps) { + /** @private @const {!Window} */ + this.win_ = deps.win(); + + /** @private @const {!./client-event-manager.ClientEventManager} */ + this.eventManager_ = deps.eventManager(); + } + + /** + * Start listening to client events + */ + start() { + this.eventManager_.registerEventListener( + this.handleClientEvent_.bind(this) + ); + } + + /** + * Listens for new events from the events manager and logs appropriate events to Google Analytics. + * @param {!../api/client-event-manager-api.ClientEvent} event + */ + handleClientEvent_(event) { + // Bail immediately if ga function doesn't exist in Window. + if (typeof this.win_.ga != 'function') { + return; + } + const gaEvent = analyticsEventToGoogleAnalyticsEvent( + event.eventType, + event.additionalParameters?.subscriptionFlow + ); + if (gaEvent) { + this.win_.ga('send', 'event', gaEvent); + } + } +} + /** * Copyright 2018 The Subscribe with Google Authors. All Rights Reserved. * @@ -15382,7 +15524,7 @@ class PayClient { 'disableNative', // The page cannot be iframed at this time. May be relaxed later // for AMP and similar contexts. - this.win_ != this.top_() + options.forceDisableNative || this.win_ != this.top_() ); let resolver = null; const promise = new Promise((resolve) => (resolver = resolve)); @@ -16255,6 +16397,7 @@ class ConfiguredRuntime { * @param {{ * fetcher: (!Fetcher|undefined), * configPromise: (!Promise|undefined), + * enableGoogleAnalytics: (boolean|undefined), * }=} integr * @param {!../api/subscriptions.Config=} config * @param {!{ @@ -16308,6 +16451,15 @@ class ConfiguredRuntime { /** @private @const {!Callbacks} */ this.callbacks_ = new Callbacks(); + // Start listening to Google Analytics events, if applicable. + if (integr.enableGoogleAnalytics) { + /** @private @const {!GoogleAnalyticsEventListener} */ + this.googleAnalyticsEventListener_ = new GoogleAnalyticsEventListener( + this + ); + this.googleAnalyticsEventListener_.start(); + } + // WARNING: DepsDef ('this') is being progressively defined below. // Constructors will crash if they rely on something that doesn't exist yet. /** @private @const {!../components/activities.ActivityPorts} */ @@ -16823,6 +16975,11 @@ class ConfiguredRuntime { }); entitlements.consume(onCloseDialog); } + + /** @override */ + showBestAudienceAction() { + warn('Not implemented yet'); + } } export { AnalyticsEvent, ClientEvent, ClientEventManagerApi, ConfiguredRuntime, DeferredAccountCreationResponse, Entitlement, Entitlements, EventOriginator, Fetcher, FilterResult, PurchaseData, SubscribeResponse, UserData };