Add MS Store install experiment (Fixes #11090)

This commit is contained in:
Alex Gibson 2024-07-11 10:21:46 +01:00
Родитель 7f7a361f4a
Коммит 05018d7896
18 изменённых файлов: 212 добавлений и 390 удалений

Просмотреть файл

@ -0,0 +1,83 @@
{#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}
{% from "macros.html" import ms_store_button with context %}
{% extends "firefox/new/desktop/download.html" %}
{% set ms_store_attribution_code = 'experiment%3Dmozorg%2Dfirefox%2Dvsinstaller%2Dexp%26variation%3Dtreatment' %}
{% macro custom_nav_cta() %}
{% set ms_store_href = ms_store_url(product='firefox', campaign=ms_store_attribution_code, handler='ms-windows-store') %}
<div class="mzp-c-button-download-container">
<a href="{{ ms_store_href }}" class="ga-product-download mzp-c-button mzp-t-product mzp-t-secondary mzp-t-md" data-cta-type="button" data-cta-text="Download Firefox">
Download Firefox
</a>
</div>
<div class="c-navigation-vpn-cta-container">
{{ vpn_product_referral_link(
referral_id='navigation',
page_anchor='#pricing',
link_text=ftl('navigation-v2-get-mozilla-vpn'),
class_name='mzp-t-product mzp-t-secondary mzp-t-md',
optional_attributes= {
'data-cta-text' : 'Get Mozilla VPN',
'data-cta-type' : 'button',
'data-cta-position' : 'navigation'
}
) }}
</div>
{% endmacro %}
{% block site_header %}
{% with custom_nav_cta=custom_nav_cta() %}
{% include 'includes/protocol/navigation/navigation.html' %}
{% endwith %}
{% endblock %}
{% block firefox_primary_download_cta %}
{% set ms_store_href = ms_store_url(product='firefox', campaign=ms_store_attribution_code, handler='ms-windows-store') %}
{{ ms_store_button(href=ms_store_href) }}
<div class="c-intro-download-alt">
<a href="{{ url('firefox.download.thanks') }}" data-cta-type="link" data-cta-text="Download from the web">
Download from the web
</a>
</div>
<small class="mzp-c-button-download-privacy-link">
<a href="{{ url('privacy.notices.firefox') }}">
{{ ftl('download-button-firefox-privacy-notice') }}
</a>
</small>
{% endblock %}
{% block firefox_secondary_download_cta %}
<div class="mzp-u-centered">
{% set ms_store_href = ms_store_url(product='firefox', campaign=ms_store_attribution_code, handler='ms-windows-store') %}
{{ ms_store_button(href=ms_store_href) }}
<small class="mzp-c-button-download-privacy-link">
<a href="{{ url('privacy.notices.firefox') }}">
{{ ftl('download-button-firefox-privacy-notice') }}
</a>
</small>
</div>
{% endblock %}
{% block firefox_tertiary_download_cta %}
<div class="mzp-u-centered">
{% set ms_store_href = ms_store_url(product='firefox', campaign=ms_store_attribution_code, handler='ms-windows-store') %}
{{ ms_store_button(href=ms_store_href) }}
<small class="mzp-c-button-download-privacy-link">
<a href="{{ url('privacy.notices.firefox') }}">
{{ ftl('download-button-firefox-privacy-notice') }}
</a>
</small>
</div>
{% endblock %}

Просмотреть файл

@ -23,11 +23,11 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% set show_firefox_install_exp = switch('experiment-firefox-thanks-install-win', ['en-US']) and country_code == "US" %} {% set show_firefox_ms_store_exp = switch('experiment-firefox-ms-store', ['en']) and country_code in ["US", "CA"] %}
{% block experiments %} {% block experiments %}
{% if show_firefox_install_exp %} {% if show_firefox_ms_store_exp %}
{{ js_bundle('firefox-thanks-install-win-exp') }} {{ js_bundle('firefox-ms-store-exp') }}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
@ -97,7 +97,9 @@
<h2 class="mzp-has-zap-7">{{ ftl('firefox-desktop-download-get-the-browser') }}</h2> <h2 class="mzp-has-zap-7">{{ ftl('firefox-desktop-download-get-the-browser') }}</h2>
<p>{{ ftl('firefox-desktop-download-no-shady') }}</p> <p>{{ ftl('firefox-desktop-download-no-shady') }}</p>
<div class="c-intro-download"> <div class="c-intro-download">
{{ download_firefox_thanks(locale_in_transition=True, download_location='primary cta') }} {% block firefox_primary_download_cta %}
{{ download_firefox_thanks(locale_in_transition=True, download_location='primary cta') }}
{% endblock %}
<div class="c-intro-download-alt"><a href="{{ url('firefox.all') }}">{{ ftl('firefox-desktop-download-download-options') }}</a></div> <div class="c-intro-download-alt"><a href="{{ url('firefox.all') }}">{{ ftl('firefox-desktop-download-download-options') }}</a></div>
@ -392,8 +394,9 @@
</ul> </ul>
</div> </div>
</div> </div>
{% block firefox_secondary_download_cta %}
{{ download_firefox_thanks(dom_id='download-features', locale_in_transition=True, download_location='features cta') }} {{ download_firefox_thanks(dom_id='download-features', locale_in_transition=True, download_location='features cta') }}
{% endblock %}
</div> </div>
</section> </section>
@ -554,8 +557,9 @@
<p>{{ ftl('firefox-desktop-download-from-watching-a') }}</p> <p>{{ ftl('firefox-desktop-download-from-watching-a') }}</p>
</div> </div>
</div> </div>
{% block firefox_tertiary_download_cta %}
{{ download_firefox_thanks(dom_id='download-discover', locale_in_transition=True, download_location='discover cta') }} {{ download_firefox_thanks(dom_id='download-discover', locale_in_transition=True, download_location='discover cta') }}
{% endblock %}
</section> </section>
<section class="c-support"> <section class="c-support">
@ -593,8 +597,4 @@
{% block js %} {% block js %}
{{ js_bundle('firefox_desktop_download') }} {{ js_bundle('firefox_desktop_download') }}
{% if show_firefox_install_exp %}
{{ js_bundle('firefox-thanks-install-win') }}
{% endif %}
{% endblock %} {% endblock %}

Просмотреть файл

@ -1,107 +0,0 @@
{#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}
{% extends "firefox/new/desktop/base.html" %}
{# FxA automated tests use this attribute to verify the page #}
{% block html_attrs %}data-test-fxa-template="firefox-download-thanks"{% endblock %}
{# "scene2" page should not be indexed to avoid it appearing in search results: issue 7024 #}
{% block canonical_urls %}<meta name="robots" content="noindex,follow">{% endblock %}
{% block extrahead %}
{{ super() }}
{{ css_bundle('firefox-thanks-install-win') }}
{% endblock %}
{% block site_header %}
{% with hide_nav_download_button=True %}
{% include 'includes/protocol/navigation/navigation.html' %}
{% endwith %}
{% endblock %}
{% set referrals = '?utm_source=www.mozilla.org&utm_medium=referral&utm_campaign=firefox-download-thanks' %}
{% block content %}
<main>
<div class="mzp-c-notification-bar mzp-t-success show-auto-download-notification">
{# fallback_url is replaced by the platform download link via JS, but if
something fails the user should still get a link to a working download path. #}
<p>
{{ ftl('firefox-desktop-download-your-firefox-new-should-begin', id='direct-download-link', fallback_url=url('firefox.all'))}}
</p>
</div>
<div class="mzp-l-content mzp-t-content-xl">
<div class="mzp-c-logo mzp-t-logo-lg mzp-t-product-firefox"></div>
<h1 class="mzp-has-zap-8 c-section-title">Almost there! <br>Just a few steps to go.</h1>
<ol class="c-install-steps mzp-l-columns mzp-t-columns-three">
<li>
<div class="c-install-steps-copy">
<h2 class="c-install-step-title">
<span>Step 1</span> Open Download
</h2>
<p>Open the Firefox Installer.exe file from the downloads list at the top right corner of this window.</p>
</div>
<div class="c-install-steps-image">
<img src="{{ static('img/firefox/new/desktop/thanks/win-step-1.svg') }}" alt="">
</div>
</li>
<li>
<div class="c-install-steps-copy">
<h2 class="c-install-step-title">
<span>Step 2</span> Allow install
</h2>
<p>If prompted, click “Install anyway” and “Yes” on the system dialog.</p>
</div>
<div class="c-install-steps-image">
<img src="{{ static('img/firefox/new/desktop/thanks/win-step-2.svg') }}" alt="">
</div>
</li>
<li>
<div class="c-install-steps-copy">
<h2 class="c-install-step-title">
<span>Step 3</span> Complete
</h2>
<p>Run the installer. Firefox will automatically open when the installation is finished.</p>
</div>
<div class="c-install-steps-image">
<img src="{{ static('img/firefox/new/desktop/thanks/win-step-3.svg') }}" alt="">
</div>
</li>
</ol>
{% if ftl_has_messages('firefox-desktop-download-if-you-see-a-prompt', 'firefox-desktop-download-visit-support-for-more') %}
<aside class="c-windows-disclaimer">
<img class="c-windows-disclaimer-logo" src="{{ static('img/logos/windows/logo-windows-black.svg') }}" alt="{{ ftl('firefox-desktop-download-windows') }}" width="132" height="28">
<p>{{ ftl('firefox-desktop-download-if-you-see-a-prompt', attrs='href="https://support.mozilla.org/kb/windows-10-warns-me-use-microsoft-verified-app%s" rel="external noopener" data-cta-type="link" data-cta-text="Get help with your installation"'|safe|format(referrals)) }}</p>
<p><a href="https://support.mozilla.org/kb/windows-10-warns-me-use-microsoft-verified-app{{ referrals }}" rel="external noopener" data-cta-type="link" data-cta-text="Visit Support for More Details">{{ ftl('firefox-desktop-download-visit-support-for-more') }}</a></p>
</aside>
{% endif %}
<div class="c-support-install">
<p>
{% set support_windows_attrs = 'href="https://support.mozilla.org/kb/how-download-and-install-firefox-windows%s" rel="external noopener" data-cta-type="link" data-cta-text="Get help with your installation"'|safe|format(referrals) %}
{{ ftl('firefox-desktop-download-get-help', attrs=support_windows_attrs) }}
</p>
</div>
{{ download_firefox(force_direct=true, dom_id='thanks-download-button') }}
</div>
<div class="c-support-lang">
<a href="{{ firefox_url('desktop', 'all') }}">{{ ftl('firefox-desktop-download-in-another-language') }}</a>
</div>
</main>
{% endblock %}
{% block js %}
{{ js_bundle('firefox_new_thanks') }}
{% endblock %}

Просмотреть файл

@ -431,27 +431,27 @@ class TestFirefoxNew(TestCase):
# end /thanks?s=direct URL - issue 10520 # end /thanks?s=direct URL - issue 10520
# begin firefox download to install experiment tests - issue 14676 # begin firefox ms store experiment tests - issue 11090
@patch.object(views, "ftl_file_is_active", lambda *x: True) @patch.object(views, "ftl_file_is_active", lambda *x: True)
def test_thanks_install_exp_v1(self, render_mock): def test_ms_store_exp_v1(self, render_mock):
req = RequestFactory().get("/firefox/download/thanks/?experiment=firefox-thanks-install-win&variation=1") req = RequestFactory().get("/firefox/new/?experiment=mozorg-firefox-vsinstaller-exp&variation=control")
req.locale = "en-US" req.locale = "en-US"
view = views.DownloadThanksView.as_view() view = views.NewView.as_view()
view(req) view(req)
template = render_mock.call_args[0][1] template = render_mock.call_args[0][1]
assert template == ["firefox/new/desktop/thanks.html"] assert template == ["firefox/new/desktop/download.html"]
@patch.object(views, "ftl_file_is_active", lambda *x: True) @patch.object(views, "ftl_file_is_active", lambda *x: True)
def test_thanks_install_exp_v2(self, render_mock): def test_ms_store_exp_v2(self, render_mock):
req = RequestFactory().get("/firefox/download/thanks/?experiment=firefox-thanks-install-win&variation=2") req = RequestFactory().get("/firefox/new/?experiment=mozorg-firefox-vsinstaller-exp&variation=treatment")
req.locale = "en-US" req.locale = "en-US"
view = views.DownloadThanksView.as_view() view = views.NewView.as_view()
view(req) view(req)
template = render_mock.call_args[0][1] template = render_mock.call_args[0][1]
assert template == ["firefox/new/desktop/thanks-install-win.html"] assert template == ["firefox/new/desktop/download-ms-store.html"]
# end firefox download to install experiment tests - issue 14676 # end firefox ms store experiment tests - issue 11090
class TestFirefoxNewNoIndex(TestCase): class TestFirefoxNewNoIndex(TestCase):

Просмотреть файл

@ -576,7 +576,6 @@ class DownloadThanksView(L10nTemplateView):
"firefox/new/basic/thanks_direct.html": ["firefox/new/download"], "firefox/new/basic/thanks_direct.html": ["firefox/new/download"],
"firefox/new/desktop/thanks.html": ["firefox/new/desktop"], "firefox/new/desktop/thanks.html": ["firefox/new/desktop"],
"firefox/new/desktop/thanks_direct.html": ["firefox/new/desktop"], "firefox/new/desktop/thanks_direct.html": ["firefox/new/desktop"],
"firefox/new/desktop/thanks-install-win.html": ["firefox/new/desktop"],
} }
activation_files = [ activation_files = [
"firefox/new/download", "firefox/new/download",
@ -584,7 +583,7 @@ class DownloadThanksView(L10nTemplateView):
] ]
# place expected ?v= values in this list # place expected ?v= values in this list
variations = ["1", "2"] variations = []
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
@ -601,15 +600,10 @@ class DownloadThanksView(L10nTemplateView):
def get_template_names(self): def get_template_names(self):
experience = self.request.GET.get("xv", None) experience = self.request.GET.get("xv", None)
source = self.request.GET.get("s", None) source = self.request.GET.get("s", None)
experiment = self.request.GET.get("experiment", None)
variation = self.request.GET.get("variation", None)
locale = l10n_utils.get_locale(self.request)
if ftl_file_is_active("firefox/new/desktop") and experience != "basic": if ftl_file_is_active("firefox/new/desktop") and experience != "basic":
if source == "direct": if source == "direct":
template = "firefox/new/desktop/thanks_direct.html" template = "firefox/new/desktop/thanks_direct.html"
elif locale == "en-US" and experiment == "firefox-thanks-install-win" and variation == "2":
template = "firefox/new/desktop/thanks-install-win.html"
else: else:
template = "firefox/new/desktop/thanks.html" template = "firefox/new/desktop/thanks.html"
else: else:
@ -625,6 +619,7 @@ class NewView(L10nTemplateView):
ftl_files_map = { ftl_files_map = {
"firefox/new/basic/base_download.html": ["firefox/new/download"], "firefox/new/basic/base_download.html": ["firefox/new/download"],
"firefox/new/desktop/download.html": ["firefox/new/desktop"], "firefox/new/desktop/download.html": ["firefox/new/desktop"],
"firefox/new/desktop/download-ms-store.html": ["firefox/new/desktop"],
} }
activation_files = [ activation_files = [
"firefox/new/download", "firefox/new/download",
@ -632,7 +627,7 @@ class NewView(L10nTemplateView):
] ]
# place expected ?v= values in this list # place expected ?v= values in this list
variations = ["1", "2"] variations = ["control", "treatment"]
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
# Remove legacy query parameters (Bug 1236791) # Remove legacy query parameters (Bug 1236791)
@ -673,13 +668,18 @@ class NewView(L10nTemplateView):
def get_template_names(self): def get_template_names(self):
variation = self.request.GET.get("variation", None) variation = self.request.GET.get("variation", None)
experience = self.request.GET.get("xv", None) experience = self.request.GET.get("xv", None)
experiment = self.request.GET.get("experiment", None)
locale = l10n_utils.get_locale(self.request)
# ensure variant matches pre-defined value # ensure variant matches pre-defined value
if variation not in self.variations: if variation not in self.variations:
variation = None variation = None
if ftl_file_is_active("firefox/new/desktop") and experience != "basic": if ftl_file_is_active("firefox/new/desktop") and experience != "basic":
template = "firefox/new/desktop/download.html" if locale.startswith("en-") and experiment == "mozorg-firefox-vsinstaller-exp" and variation == "treatment":
template = "firefox/new/desktop/download-ms-store.html"
else:
template = "firefox/new/desktop/download.html"
else: else:
template = "firefox/new/basic/base_download.html" template = "firefox/new/basic/base_download.html"

Просмотреть файл

@ -630,13 +630,18 @@ def play_store_url(ctx, product, campaign=None):
@library.global_function @library.global_function
@jinja2.pass_context @jinja2.pass_context
def ms_store_url(ctx, product, mode="direct", campaign=None): def ms_store_url(ctx, product="firefox", mode="mini", campaign=None, handler=None):
""" """
Returns a Microsoft Windows Store URL for a given product. Returns a Microsoft Windows Store URL for a given product.
Installer mode parameter options include "direct" or "full", or "mini". Installer mode parameter options include "direct" or "full", or "mini".
See https://apps.microsoft.com/badge for details. See https://apps.microsoft.com/badge for details.
""" """
base_url = getattr(settings, f"MICROSOFT_WINDOWS_STORE_{product.upper()}_LINK")
if handler == "ms-windows-store":
base_url = getattr(settings, f"MICROSOFT_WINDOWS_STORE_{product.upper()}_DIRECT_LINK")
else:
base_url = getattr(settings, f"MICROSOFT_WINDOWS_STORE_{product.upper()}_WEB_LINK")
params = { params = {
"mode": mode, "mode": mode,
"cid": campaign, "cid": campaign,

Просмотреть файл

@ -866,32 +866,44 @@ class TestPlayStoreURL(TestCase):
class TestMSStoreURL(TestCase): class TestMSStoreURL(TestCase):
rf = RequestFactory() rf = RequestFactory()
def _render(self, product, mode="direct", campaign=None): def _render(self, product, mode="mini", campaign=None, handler=None):
req = self.rf.get("/") req = self.rf.get("/")
campaign_param = f"'{campaign}'" if campaign is not None else campaign campaign_param = f"'{campaign}'" if campaign is not None else campaign
handler_param = f"'{handler}'" if handler is not None else handler
return render( return render(
f"{{{{ ms_store_url('{product}', '{mode}', {campaign_param}) }}}}", f"{{{{ ms_store_url('{product}', '{mode}', {campaign_param}, {handler_param}) }}}}",
{"request": req}, {"request": req},
) )
def test_firefox_release_ms_store_url(self): def test_firefox_release_ms_store_url(self):
"""should return a MS Store URL for Firefox release channel""" """should return a MS Store URL for Firefox release channel"""
assert self._render(product="firefox") == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=direct" assert self._render(product="firefox") == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=mini"
def test_firefox_beta_ms_store_url(self): def test_firefox_beta_ms_store_url(self):
"""should return a MS Store URL for Firefox Beta channel""" """should return a MS Store URL for Firefox Beta channel"""
assert self._render(product="firefox_beta") == "https://apps.microsoft.com/detail/9nzw26frndln?mode=direct" assert self._render(product="firefox_beta") == "https://apps.microsoft.com/detail/9nzw26frndln?mode=mini"
def test_firefox_ms_store_url_launch_mode(self): def test_firefox_ms_store_url_launch_mode(self):
"""should return a MS Store URL including different launch mode parameters""" """should return a MS Store URL including different launch mode parameters"""
assert self._render(product="firefox", mode="full") == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=full" assert self._render(product="firefox", mode="full") == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=full"
assert self._render(product="firefox", mode="mini") == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=mini" assert self._render(product="firefox", mode="direct") == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=direct"
def test_firefox_ms_store_url_campaign(self): def test_firefox_ms_store_url_campaign(self):
"""should return a MS Store URL including campaign parameters""" """should return a MS Store URL including campaign parameters"""
assert ( assert (
self._render(product="firefox", campaign="mozorg-firefox-home") self._render(product="firefox", campaign="mozorg-firefox-home")
== "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=direct&amp;cid=mozorg-firefox-home" == "https://apps.microsoft.com/detail/9nzvdkpmr9rd?mode=mini&amp;cid=mozorg-firefox-home"
)
def test_firefox_ms_store_url_protocol_handler(self):
"""should return a MS Store URL including campaign parameters"""
assert (
self._render(product="firefox", campaign="mozorg-firefox-home", handler="ms-windows-store")
== "ms-windows-store://pdp/?productid=9nzvdkpmr9rd&amp;mode=mini&amp;cid=mozorg-firefox-home"
)
assert (
self._render(product="firefox_beta", campaign="mozorg-firefox-home", handler="ms-windows-store")
== "ms-windows-store://pdp/?productid=9nzw26frndln&amp;mode=mini&amp;cid=mozorg-firefox-home"
) )

Просмотреть файл

@ -107,7 +107,13 @@ AMAZON_FIREFOX_FIRE_TV_LINK = "https://www.amazon.com/Mozilla-Firefox-for-Fire-T
GOOGLE_PLAY_FIREFOX_SEND_LINK = "https://play.google.com/store/apps/details?id=org.mozilla.firefoxsend" GOOGLE_PLAY_FIREFOX_SEND_LINK = "https://play.google.com/store/apps/details?id=org.mozilla.firefoxsend"
# Link to Firefox on the Microsoft Windows Store. # Link to Firefox on the Microsoft Windows Store.
MICROSOFT_WINDOWS_STORE_FIREFOX_LINK = "https://apps.microsoft.com/detail/9nzvdkpmr9rd" MICROSOFT_WINDOWS_STORE_FIREFOX_WEB_LINK = "https://apps.microsoft.com/detail/9nzvdkpmr9rd"
# Link to Firefox on the Microsoft Windows Store with custom protocol handler.
MICROSOFT_WINDOWS_STORE_FIREFOX_DIRECT_LINK = "ms-windows-store://pdp/?productid=9nzvdkpmr9rd"
# Link to Firefox Beta on the Microsoft Windows Store. # Link to Firefox Beta on the Microsoft Windows Store.
MICROSOFT_WINDOWS_STORE_FIREFOX_BETA_LINK = "https://apps.microsoft.com/detail/9nzw26frndln" MICROSOFT_WINDOWS_STORE_FIREFOX_BETA_WEB_LINK = "https://apps.microsoft.com/detail/9nzw26frndln"
# Link to Firefox Beta on the Microsoft Windows Store with custom protocol handler.
MICROSOFT_WINDOWS_STORE_FIREFOX_BETA_DIRECT_LINK = "ms-windows-store://pdp/?productid=9nzw26frndln"

Просмотреть файл

@ -1030,8 +1030,10 @@ from .appstores import ( # noqa: E402, F401
GOOGLE_PLAY_FOCUS_LINK, GOOGLE_PLAY_FOCUS_LINK,
GOOGLE_PLAY_KLAR_LINK, GOOGLE_PLAY_KLAR_LINK,
GOOGLE_PLAY_POCKET_LINK, GOOGLE_PLAY_POCKET_LINK,
MICROSOFT_WINDOWS_STORE_FIREFOX_BETA_LINK, MICROSOFT_WINDOWS_STORE_FIREFOX_BETA_DIRECT_LINK,
MICROSOFT_WINDOWS_STORE_FIREFOX_LINK, MICROSOFT_WINDOWS_STORE_FIREFOX_BETA_WEB_LINK,
MICROSOFT_WINDOWS_STORE_FIREFOX_DIRECT_LINK,
MICROSOFT_WINDOWS_STORE_FIREFOX_WEB_LINK,
) )
# Locales that should display the 'Send to Device' widget # Locales that should display the 'Send to Device' widget

Просмотреть файл

@ -1,171 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
$font-path: '/media/protocol/fonts';
$image-path: '/media/protocol/img';
@import '~@mozilla-protocol/core/protocol/css/includes/lib';
@import '~@mozilla-protocol/core/protocol/css/components/logos/logo';
@import '~@mozilla-protocol/core/protocol/css/components/logos/logo-product-firefox';
@import '~@mozilla-protocol/core/protocol/css/components/notification-bar';
@import '~@mozilla-protocol/core/protocol/css/components/zap';
@import '~@mozilla-protocol/core/protocol/css/templates/multi-column';
// --------------------------------------------------------------------------
// Protocol over-rides
// https://github.com/mozilla/protocol/issues/345
// https://github.com/mozilla/protocol/issues/536
// xs
$v-grid-xs: $layout-md;
$h-grid-xs: $layout-xs;
// md
$v-grid-md: $layout-xl * 0.5;
$h-grid-md: 64px;
// lg
$v-grid-lg: 192px * 0.5;
$h-grid-lg: 80px;
body {
background-color: $color-light-gray-10;
}
main {
color: $color-dark-gray-30;
.mzp-l-content {
padding-top: $v-grid-xs;
padding-bottom: $v-grid-xs;
@media #{$mq-md} {
padding-top: $v-grid-md;
padding-bottom: $v-grid-md;
}
@media #{$mq-lg} {
padding-top: $v-grid-lg;
padding-bottom: $v-grid-lg;
}
}
.mzp-c-logo {
margin-left: auto;
margin-right: auto;
}
h1 {
color: $color-marketing-gray-99;
margin-bottom: $spacing-md;
}
}
// Hide the /thanks download button as selection is made via JS automatically.
#thanks-download-button {
display: none;
}
// --------------------------------------------------------------------------
// installation-instructions
.c-install-steps {
margin: $layout-xl auto 0;
li {
display: flex;
flex-direction: column;
}
.c-install-steps-copy {
background-color: $color-white;
border-top-left-radius: 20px;
border-top-right-radius: 20px;
padding: $spacing-lg $spacing-lg 0;
flex: 1
}
.c-install-step-title {
@include text-title-xs;
span {
@include font-size(18px);
color: $color-dark-gray-05;
display: block;
margin-bottom: $spacing-md;
text-transform: uppercase;
}
}
.c-install-steps-image {
align-items: center;
align-self: flex-end;
background-color: #3d79f5;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
display: flex;
justify-content: center;
min-height: 165px;
width: 100%;
}
li:nth-child(1) .c-install-steps-image {
background: linear-gradient(270deg, #088dee 0%, #2c7ff3 100%);
}
li:nth-child(2) .c-install-steps-image {
background: linear-gradient(270deg, #3d79f5 0%, #616bf9 100%);
}
li:nth-child(3) .c-install-steps-image {
background: linear-gradient(270deg, #616bf9 0%, #616bf9 100%);
}
}
// --------------------------------------------------------------------------
// section titles
.c-section-title {
@include text-title-md;
margin: 0 auto $layout-sm;
padding: 0 $layout-sm;
max-width: $content-md;
text-align: center;
strong {
white-space: nowrap;
}
}
// --------------------------------------------------------------------------
// windows disclaimer
.c-windows-disclaimer {
margin: $layout-xl auto $layout-sm;
max-width: $content-sm;
text-align: center;
.c-windows-disclaimer-logo {
margin-bottom: $layout-xs;
}
p:last-child {
margin-bottom: 0;
}
}
// --------------------------------------------------------------------------
.c-support-install {
margin: 0 auto;
max-width: 30em;
padding: $spacing-xl $spacing-lg $spacing-lg;
text-align: center;
}
.c-support-lang {
background-color: $color-light-gray-20;
padding: $spacing-lg;
text-align: center;
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 35 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 16 KiB

Просмотреть файл

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="195" height="102" fill="none" viewBox="0 0 195 102"><path fill="#333336" stroke="#333336" stroke-width=".669" d="M5.029 10.731a3.656 3.656 0 0 1 3.656-3.656h181.981a3.656 3.656 0 0 1 3.656 3.656v8.905H5.029v-8.905Z"/><path fill="#333336" stroke="#333336" stroke-linecap="round" stroke-linejoin="round" stroke-width=".669" d="M16.948 15.595c1.612 0 2.918-.866 2.918-1.935s-1.306-1.935-2.918-1.935-2.919.866-2.919 1.935 1.307 1.935 2.919 1.935ZM29.178 15.596c1.611 0 2.918-.867 2.918-1.936 0-1.068-1.306-1.935-2.918-1.935s-2.92.867-2.92 1.935c0 1.07 1.308 1.936 2.92 1.936ZM41.425 15.596c1.612 0 2.919-.867 2.919-1.936 0-1.068-1.307-1.935-2.919-1.935s-2.919.867-2.919 1.935c0 1.07 1.307 1.936 2.919 1.936Z"/><path stroke="#333336" stroke-linecap="round" stroke-linejoin="round" stroke-width=".669" d="m181.479 11.88 5.372 3.549M181.479 15.429l5.372-3.55"/><path fill="#333336" stroke="#333336" stroke-width=".669" d="M5.029 20.305h189.293v77.706a3.654 3.654 0 0 1-3.655 3.654H8.683a3.654 3.654 0 0 1-3.654-3.654V20.305Z"/><mask id="a" fill="#fff"><path d="M0 15h190v79.01a3.99 3.99 0 0 1-3.989 3.99H3.989A3.99 3.99 0 0 1 0 94.01V15Z"/></mask><path fill="#fff" d="M0 15h190v79.01a3.99 3.99 0 0 1-3.989 3.99H3.989A3.99 3.99 0 0 1 0 94.01V15Z"/><path fill="#333336" d="M0 15h190H0Zm191.249 79.01a5.238 5.238 0 0 1-5.238 5.24H3.989a5.239 5.239 0 0 1-5.238-5.24h2.498a2.74 2.74 0 0 0 2.74 2.74h182.022a2.74 2.74 0 0 0 2.74-2.74h2.498ZM3.989 99.25a5.239 5.239 0 0 1-5.238-5.24V15h2.498v79.01a2.74 2.74 0 0 0 2.74 2.74v2.5ZM191.25 15v79.01a5.238 5.238 0 0 1-5.238 5.24v-2.5a2.74 2.74 0 0 0 2.74-2.74V15h2.498Z" mask="url(#a)"/><path fill="#DCD4FF" stroke="#333336" stroke-width="1.249" d="M.625 3.99A3.366 3.366 0 0 1 3.99.626h182.018a3.366 3.366 0 0 1 3.366 3.366V17.59H.625V3.99Z"/><path stroke="#333336" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.249" d="m176.785 7.75 5.372 5.354M176.785 13.104l5.372-5.354"/><rect width="148.18" height="10.18" x="22.41" y="58.41" fill="#fff" stroke="#333336" stroke-width=".82" rx="1.09"/><path fill="#9059FF" stroke="#333336" stroke-width=".82" d="M22.41 59.5c0-.602.488-1.09 1.09-1.09h82.09v10.18H23.5a1.09 1.09 0 0 1-1.09-1.09v-8Z"/><path fill="#000" d="M22.869 49v-7.557h3.069c1.562 0 2.783 1.001 2.783 2.42s-1.221 2.42-2.783 2.42h-2.211V49h-.858Zm.858-3.531h2.057c1.232 0 2.068-.594 2.068-1.606s-.836-1.606-2.068-1.606h-2.057v3.212Zm7.09-1.045c.341-.759 1.155-1.243 2.2-1.243v.737c-1.287 0-2.2.792-2.2 1.903V49h-.825v-5.687h.825v1.111Zm5.799 4.708c-1.595 0-2.948-1.364-2.948-2.981 0-1.617 1.353-2.97 2.948-2.97s2.937 1.353 2.937 2.97c0 1.617-1.342 2.981-2.937 2.981Zm0-.737c1.122 0 2.068-1.023 2.068-2.244 0-1.21-.946-2.233-2.068-2.233-1.133 0-2.08 1.023-2.08 2.233 0 1.221.947 2.244 2.08 2.244Zm8.721-5.082h.825v5.082c0 1.463-1.155 2.497-2.794 2.497-.924 0-1.782-.319-2.299-.759l.363-.649c.44.418 1.122.671 1.826.671 1.31 0 2.08-.649 2.08-1.76v-.924c-.44.693-1.167 1.111-2.069 1.111-1.529 0-2.618-1.122-2.618-2.706 0-1.584 1.09-2.695 2.618-2.695.902 0 1.628.418 2.068 1.111v-.979Zm-1.914 4.532c1.122 0 1.914-.814 1.914-1.969 0-1.144-.792-1.958-1.914-1.958-1.11 0-1.903.814-1.903 1.958 0 1.155.792 1.969 1.903 1.969Zm5.387-3.421c.341-.759 1.155-1.243 2.2-1.243v.737c-1.287 0-2.2.792-2.2 1.903V49h-.825v-5.687h.825v1.111Zm5.904 3.971c.671 0 1.441-.297 1.793-.682l.506.539c-.495.539-1.496.88-2.288.88-1.518 0-2.882-1.243-2.882-2.992 0-1.694 1.276-2.959 2.805-2.959 1.716 0 2.695 1.298 2.695 3.289H52.69c.121 1.111.902 1.925 2.024 1.925Zm-.033-4.477c-1.012 0-1.826.715-1.98 1.815h3.828c-.11-1.023-.715-1.815-1.848-1.815Zm6.025 5.214a3.862 3.862 0 0 1-2.354-.847l.43-.605c.648.473 1.297.715 1.924.715.748 0 1.254-.352 1.254-.891 0-.616-.66-.814-1.43-1.034-1.375-.396-1.903-.803-1.903-1.617 0-1.034.858-1.672 1.991-1.672.704 0 1.43.242 2.035.638l-.396.638c-.572-.363-1.133-.539-1.639-.539-.638 0-1.166.286-1.166.836 0 .495.418.649 1.474.99.913.286 1.86.594 1.86 1.672 0 1.045-.903 1.716-2.08 1.716Zm5.457 0a3.862 3.862 0 0 1-2.353-.847l.428-.605c.65.473 1.299.715 1.925.715.749 0 1.255-.352 1.255-.891 0-.616-.66-.814-1.43-1.034-1.376-.396-1.903-.803-1.903-1.617 0-1.034.858-1.672 1.99-1.672.704 0 1.43.242 2.035.638l-.395.638c-.573-.363-1.133-.539-1.64-.539-.638 0-1.166.286-1.166.836 0 .495.418.649 1.474.99.913.286 1.86.594 1.86 1.672 0 1.045-.902 1.716-2.08 1.716Z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 4.3 KiB

Просмотреть файл

@ -13,6 +13,7 @@ const appStoreURL = /^https:\/\/apps.apple.com/;
const playStoreURL = /^https:\/\/play.google.com/; const playStoreURL = /^https:\/\/play.google.com/;
const marketURL = /^market:\/\/play.google.com/; const marketURL = /^market:\/\/play.google.com/;
const msStoreUrl = /^https:\/\/apps.microsoft.com/; const msStoreUrl = /^https:\/\/apps.microsoft.com/;
const msStoreUrl2 = /^ms-windows-store:\/\/pdp\//;
if (typeof window.dataLayer === 'undefined') { if (typeof window.dataLayer === 'undefined') {
window.dataLayer = []; window.dataLayer = [];
@ -33,7 +34,8 @@ TrackProductDownload.isValidDownloadURL = (downloadURL) => {
appStoreURL.test(downloadURL) || appStoreURL.test(downloadURL) ||
playStoreURL.test(downloadURL) || playStoreURL.test(downloadURL) ||
marketURL.test(downloadURL) || marketURL.test(downloadURL) ||
msStoreUrl.test(downloadURL) msStoreUrl.test(downloadURL) ||
msStoreUrl2.test(downloadURL)
) { ) {
return true; return true;
} else { } else {
@ -184,11 +186,11 @@ TrackProductDownload.getEventFromUrl = (downloadURL) => {
'store', 'store',
'release' 'release'
); );
} else if (msStoreUrl.test(downloadURL)) { } else if (msStoreUrl.test(downloadURL) || msStoreUrl2.test(downloadURL)) {
let channel = 'unrecognized'; let channel = 'unrecognized';
if (downloadURL.indexOf('/9nzvdkpmr9rd') !== -1) { if (downloadURL.indexOf('9nzvdkpmr9rd') !== -1) {
channel = 'release'; channel = 'release';
} else if (downloadURL.indexOf('/9nzw26frndln') !== -1) { } else if (downloadURL.indexOf('9nzw26frndln') !== -1) {
channel = 'beta'; channel = 'beta';
} }

Просмотреть файл

@ -9,44 +9,50 @@ import { isApprovedToRun } from '../../../base/experiment-utils.es6.js';
const href = window.location.href; const href = window.location.href;
function isEdgeBrowser() {
return (
navigator.userAgent.indexOf('Edg') !== -1 ||
navigator.userAgent.indexOf('Edge') !== -1
);
}
function isWindows10Plus() { function isWindows10Plus() {
const match = navigator.userAgent.match(/Windows NT (\d+\.\d+)/); const match = navigator.userAgent.match(/Windows NT (\d+\.\d+)/);
return match && parseFloat(match[1]) >= 10.0; return match && parseFloat(match[1]) >= 10.0;
} }
function isFirefox() {
return (
/\s(Firefox|FxiOS)/.test(navigator.userAgent) &&
!/Iceweasel|IceCat|SeaMonkey|Camino|like Firefox/i.test(
navigator.userAgent
)
);
}
const initTrafficCop = () => { const initTrafficCop = () => {
if ( if (
href.indexOf('experiment=firefox-thanks-install-win&variation=1') !== -1 href.indexOf(
'experiment=mozorg-firefox-vsinstaller-exp&variation=control'
) !== -1
) { ) {
window.dataLayer.push({ window.dataLayer.push({
event: 'experiment_view', event: 'experiment_view',
id: 'firefox-thanks-install-win', id: 'mozorg-firefox-vsinstaller-exp',
variant: '1' variant: 'control'
}); });
} else if ( } else if (
href.indexOf('experiment=firefox-thanks-install-win&variation=2') !== -1 href.indexOf(
'experiment=mozorg-firefox-vsinstaller-exp&variation=treatment'
) !== -1
) { ) {
window.dataLayer.push({ window.dataLayer.push({
event: 'experiment_view', event: 'experiment_view',
id: 'firefox-thanks-install-win', id: 'mozorg-firefox-vsinstaller-exp',
variant: '2' variant: 'treatment'
}); });
} else if (TrafficCop) { } else if (TrafficCop) {
/** /**
* Experiment is targeted at Windows 10 or greater using Edge browser. * Experiment is targeted at Windows 10 or greater and non-Firefox browsers.
*/ */
if (isApprovedToRun() && isWindows10Plus() && isEdgeBrowser()) { if (isApprovedToRun() && isWindows10Plus() && !isFirefox()) {
const cop = new TrafficCop({ const cop = new TrafficCop({
variations: { variations: {
'experiment=firefox-thanks-install-win&variation=1': 25, // control 'experiment=mozorg-firefox-vsinstaller-exp&variation=control': 25,
'experiment=firefox-thanks-install-win&variation=2': 25 // install messaging 'experiment=mozorg-firefox-vsinstaller-exp&variation=treatment': 25
} }
}); });
cop.init(); cop.init();

Просмотреть файл

@ -1,31 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const variation = document.querySelector('main').getAttribute('data-variation');
/**
* Update download links with the experiment and variation query parameters.
*/
function updateDownloadLinks() {
const downloadLinks = document.querySelectorAll(
'.c-button-download-thanks-link'
);
for (let i = 0; i < downloadLinks.length; ++i) {
const link = downloadLinks[i];
const href = link.getAttribute('href');
if (href) {
const separator = href.indexOf('?') !== -1 ? '&' : '?';
link.setAttribute(
'href',
`${href}${separator}experiment=firefox-thanks-install-win&variation=${variation}`
);
}
}
}
if (variation === '1' || variation === '2') {
updateDownloadLinks();
}

Просмотреть файл

@ -133,12 +133,6 @@
], ],
"name": "firefox_desktop_download_thanks" "name": "firefox_desktop_download_thanks"
}, },
{
"files": [
"css/firefox/new/desktop/thanks-install-win.scss"
],
"name": "firefox-thanks-install-win"
},
{ {
"files": [ "files": [
"css/firefox/new/desktop/thanks-ie.scss" "css/firefox/new/desktop/thanks-ie.scss"
@ -1316,15 +1310,9 @@
}, },
{ {
"files": [ "files": [
"js/firefox/new/desktop/thanks-install-win-exp.es6.js" "js/firefox/new/desktop/download-ms-store-exp.es6.js"
], ],
"name": "firefox-thanks-install-win-exp" "name": "firefox-ms-store-exp"
},
{
"files": [
"js/firefox/new/desktop/thanks-install-win.es6.js"
],
"name": "firefox-thanks-install-win"
}, },
{ {
"files": [ "files": [

Просмотреть файл

@ -48,6 +48,18 @@ describe('TrackProductDownload.isValidDownloadURL', function () {
); );
expect(testPlayStoreURL).toBe(true); expect(testPlayStoreURL).toBe(true);
}); });
it('should recognize the MS Store as a valid URL', function () {
const testMsStoreURL = TrackProductDownload.isValidDownloadURL(
'https://apps.microsoft.com/detail/9nzvdkpmr9rd'
);
expect(testMsStoreURL).toBe(true);
});
it('should recognize ms-windows-store:// as a valid URL', function () {
const testMsStoreURL = TrackProductDownload.isValidDownloadURL(
'ms-windows-store://pdp/?productid=9nzvdkpmr9rd'
);
expect(testMsStoreURL).toBe(true);
});
it('should not accept a random link to mozilla.org as a valid URL', function () { it('should not accept a random link to mozilla.org as a valid URL', function () {
const testRandomURL = TrackProductDownload.isValidDownloadURL( const testRandomURL = TrackProductDownload.isValidDownloadURL(
'https://www.mozilla.org/en-US/firefox/all/' 'https://www.mozilla.org/en-US/firefox/all/'
@ -312,6 +324,24 @@ describe('TrackProductDownload.getEventFromUrl', function () {
expect(testEvent['method']).toBe('store'); expect(testEvent['method']).toBe('store');
expect(testEvent['release_channel']).toBe('beta'); expect(testEvent['release_channel']).toBe('beta');
}); });
it('should identify Firefox in the MS Store using ms-windows-store protocol handler', function () {
const testEvent = TrackProductDownload.getEventFromUrl(
'ms-windows-store://pdp/?productid=9nzvdkpmr9rd'
);
expect(testEvent['product']).toBe('firefox');
expect(testEvent['platform']).toBe('win');
expect(testEvent['method']).toBe('store');
expect(testEvent['release_channel']).toBe('release');
});
it('should identify Firefox Beta in the MS Store using ms-windows-store protocol handler', function () {
const testEvent = TrackProductDownload.getEventFromUrl(
'ms-windows-store://pdp/?productid=9nzw26frndln'
);
expect(testEvent['product']).toBe('firefox');
expect(testEvent['platform']).toBe('win');
expect(testEvent['method']).toBe('store');
expect(testEvent['release_channel']).toBe('beta');
});
}); });
describe('TrackProductDownload.handleLink', function () { describe('TrackProductDownload.handleLink', function () {