diff --git a/bedrock/base/templates/base-protocol.html b/bedrock/base/templates/base-protocol.html index 33f71c2b24..e144cde145 100644 --- a/bedrock/base/templates/base-protocol.html +++ b/bedrock/base/templates/base-protocol.html @@ -152,7 +152,7 @@ {% endblock %} diff --git a/bedrock/firefox/redirects.py b/bedrock/firefox/redirects.py index 607d6f2baa..ce6fc0b1b4 100644 --- a/bedrock/firefox/redirects.py +++ b/bedrock/firefox/redirects.py @@ -632,4 +632,6 @@ redirectpatterns = ( redirect(r"^firefox/privacy/safe-passwords/?$", "firefox.features.password-manager"), redirect(r"^firefox/privacy/book/?$", "https://support.mozilla.org/kb/how-stay-safe-web"), redirect(r"^firefox/nothingpersonal/?$", "firefox.nothing-personal.index"), + # issue 15841 + redirect(r"^firefox/tech/?$", "firefox.landing.tech"), ) diff --git a/bedrock/firefox/templates/firefox/landing/tech.html b/bedrock/firefox/templates/firefox/landing/tech.html new file mode 100644 index 0000000000..56059a9166 --- /dev/null +++ b/bedrock/firefox/templates/firefox/landing/tech.html @@ -0,0 +1,57 @@ +{# + 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/download.html" %} + +{% block canonical_urls %}{% endblock %} + +{% set win_custom_download_id = 'partner-firefox-release-smi-smi-001-stub' %} +{% set mac_custom_download_id = 'partner-firefox-release-smi-smi-001-latest' %} + +{% set android_campaign_url = play_store_url('firefox', 'custom-001') %} +{% set ios_campaign_url = app_store_url('firefox', 'custom-001') %} + +{% block string_data %} + data-win-custom-id="{{ win_custom_download_id }}" + data-mac-custom-id="{{ mac_custom_download_id }}" +{% endblock %} + +{% block primary_cta %} + {{ download_firefox(dom_id='download-primary', force_direct=True, download_location='primary cta') }} +{% endblock %} + +{% block features_cta %} + {{ download_firefox(dom_id='download-features', force_direct=True, download_location='features cta') }} +{% endblock %} + +{% block discover_cta %} + {{ download_firefox(dom_id='download-discover', force_direct=True, download_location='discover cta') }} +{% endblock %} + +{% block mobile_primary_cta %} +
+ {{ google_play_button(href=android_campaign_url) }} +
+
+ {{ apple_app_store_button(href=ios_campaign_url) }} +
+{% endblock %} + +{% block mobile_secondary_cta %} + +{% endblock %} + +{% block js %} + {{ super() }} + {{ js_bundle('firefox_partner_build_download') }} +{% endblock %} diff --git a/bedrock/firefox/templates/firefox/new/desktop/download.html b/bedrock/firefox/templates/firefox/new/desktop/download.html index 654b7d9a82..759f75458e 100644 --- a/bedrock/firefox/templates/firefox/new/desktop/download.html +++ b/bedrock/firefox/templates/firefox/new/desktop/download.html @@ -89,7 +89,9 @@

{{ ftl('firefox-desktop-download-get-the-browser') }}

{{ ftl('firefox-desktop-download-no-shady') }}

- {{ download_firefox_thanks(locale_in_transition=True, download_location='primary cta') }} + {% block primary_cta %} + {{ download_firefox_thanks(locale_in_transition=True, download_location='primary cta') }} + {% endblock %}
{{ ftl('firefox-desktop-download-download-options') }}
@@ -279,14 +281,16 @@

{{ ftl('firefox-desktop-download-all-your-devices') }}

{{ ftl('firefox-desktop-download-take-your-privacy') }}

- + {% block mobile_secondary_cta %} + + {% endblock %}
@@ -384,8 +388,9 @@
- {{ download_firefox_thanks(dom_id='download-features', locale_in_transition=True, download_location='features cta') }} - + {% block features_cta %} + {{ download_firefox_thanks(dom_id='download-features', locale_in_transition=True, download_location='features cta') }} + {% endblock %} @@ -545,7 +550,9 @@

{{ ftl('firefox-desktop-download-from-watching-a') }}

- {{ download_firefox_thanks(dom_id='download-discover', locale_in_transition=True, download_location='discover cta') }} + {% block discover_cta %} + {{ download_firefox_thanks(dom_id='download-discover', locale_in_transition=True, download_location='discover cta') }} + {% endblock %}
@@ -563,12 +570,14 @@

{{ ftl('firefox-desktop-download-download-the-mobile') }}

-
- {{ google_play_button() }} -
-
- {{ apple_app_store_button(href=ios_url) }} -
+ {% block mobile_primary_cta %} +
+ {{ google_play_button() }} +
+
+ {{ apple_app_store_button(href=ios_url) }} +
+ {% endblock %} diff --git a/bedrock/firefox/urls.py b/bedrock/firefox/urls.py index 59b4350acc..75c7f3515b 100644 --- a/bedrock/firefox/urls.py +++ b/bedrock/firefox/urls.py @@ -270,6 +270,8 @@ urlpatterns = ( "firefox/firefox-20th/index.html", active_locales=["de", "fr", "en-US", "en-CA", "en-GB"], ), + # Issue 15841 - UK influencer campaign + page("firefox/landing/tech/", "firefox/landing/tech.html", ftl_files="firefox/new/desktop", active_locales="en-GB"), ) # Contentful diff --git a/bedrock/settings/base.py b/bedrock/settings/base.py index 510c1399b6..42557766ac 100644 --- a/bedrock/settings/base.py +++ b/bedrock/settings/base.py @@ -504,6 +504,7 @@ NOINDEX_URLS = [ r"^firefox/this-browser-comes-highly-recommended/", r"^firefox/nightly/notes/feed/$", r"^firefox.*/all/$", + r"^firefox/landing/", r"^.+/(firstrun|whatsnew)/$", r"^m/", r"^newsletter/(confirm|existing|hacks\.mozilla\.org|recovery|updated|fxa-error)/", diff --git a/media/js/base/consent/allow-list.es6.js b/media/js/base/consent/allow-list.es6.js index 8c6d52020c..db257993ae 100644 --- a/media/js/base/consent/allow-list.es6.js +++ b/media/js/base/consent/allow-list.es6.js @@ -7,6 +7,7 @@ const MozAllowList = [ '/firefox/built-for-you/', '/firefox/challenge-the-default/', + '/firefox/landing/*', '/newsletter/firefox/', '/products/vpn/*' ]; diff --git a/media/js/base/datalayer-productdownload.es6.js b/media/js/base/datalayer-productdownload.es6.js index 2f0ec2fca8..940b98c3c1 100644 --- a/media/js/base/datalayer-productdownload.es6.js +++ b/media/js/base/datalayer-productdownload.es6.js @@ -112,7 +112,9 @@ TrackProductDownload.getEventFromUrl = (downloadURL) => { const productParam = params.product; const productSplit = productParam.split('-'); // product is first word of product param - const product = productSplit[0]; + let product = productSplit[0]; + // partner builds are labelled as ?product=partner-firefox so class these as regular 'firefox' download events. + product = product === 'partner' ? 'firefox' : product; let platform = params.os; // change platform to macos if it's osx platform = platform === 'osx' ? 'macos' : platform; diff --git a/media/js/firefox/landing/partner-build-download-init.es6.js b/media/js/firefox/landing/partner-build-download-init.es6.js new file mode 100644 index 0000000000..7dc46226a2 --- /dev/null +++ b/media/js/firefox/landing/partner-build-download-init.es6.js @@ -0,0 +1,9 @@ +/* + * 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/. + */ + +import PartnerBuildDownload from './partner-build-download.es6'; + +PartnerBuildDownload.init(); diff --git a/media/js/firefox/landing/partner-build-download.es6.js b/media/js/firefox/landing/partner-build-download.es6.js new file mode 100644 index 0000000000..4d6a28c8a3 --- /dev/null +++ b/media/js/firefox/landing/partner-build-download.es6.js @@ -0,0 +1,56 @@ +/* + * 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 PartnerBuildDownload = {}; + +let winDownloadID; +let macDownloadID; + +PartnerBuildDownload.createCustomDownloadURL = (link, id) => { + const url = new URL(link.href); + + // update product to custom build ID. + url.searchParams.set('product', id); + + link.href = url; +}; + +PartnerBuildDownload.replaceWithCustomDownloadLinks = () => { + const downloadLinksWin = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="win"]' + ) + ); + const downloadLinksMac = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="osx"]' + ) + ); + + downloadLinksWin.forEach((link) => + PartnerBuildDownload.createCustomDownloadURL(link, winDownloadID) + ); + downloadLinksMac.forEach((link) => + PartnerBuildDownload.createCustomDownloadURL(link, macDownloadID) + ); +}; + +PartnerBuildDownload.init = () => { + const strings = document.getElementById('strings'); + winDownloadID = strings.getAttribute('data-win-custom-id'); + macDownloadID = strings.getAttribute('data-mac-custom-id'); + + if ( + typeof window.URL === 'function' && + typeof Array.from === 'function' && + winDownloadID && + macDownloadID + ) { + PartnerBuildDownload.replaceWithCustomDownloadLinks(); + } +}; + +export default PartnerBuildDownload; diff --git a/media/static-bundles.json b/media/static-bundles.json index e51f53d0ee..d450ab4339 100644 --- a/media/static-bundles.json +++ b/media/static-bundles.json @@ -1788,6 +1788,12 @@ "js/base/banners/fundraiser-experiment.es6.js" ], "name": "fundraising-banner-experiment" + }, + { + "files": [ + "js/firefox/landing/partner-build-download-init.es6.js" + ], + "name": "firefox_partner_build_download" } ] } diff --git a/tests/redirects/map_globalconf.py b/tests/redirects/map_globalconf.py index 87e7faa15e..48dd80cc24 100644 --- a/tests/redirects/map_globalconf.py +++ b/tests/redirects/map_globalconf.py @@ -1328,5 +1328,7 @@ URLS = flatten( ), # Issue 15386 url_test("/products/vpn/resource-center/no-Logging-vpn-from-mozilla/", "/products/vpn/resource-center/no-logging-vpn-from-mozilla/"), + # Issue 15841 + url_test("/firefox/tech/", "/firefox/landing/tech/"), ) ) diff --git a/tests/unit/spec/base/datalayer-productdownload.js b/tests/unit/spec/base/datalayer-productdownload.js index 1eb6b61bcc..8f2e7ebd65 100644 --- a/tests/unit/spec/base/datalayer-productdownload.js +++ b/tests/unit/spec/base/datalayer-productdownload.js @@ -111,6 +111,12 @@ describe('TrackProductDownload.getEventFromUrl', function () { ); expect(testEvent['product']).toBe('firefox'); }); + it('should identify product for Firefox Desktop partner builds', function () { + const testEvent = TrackProductDownload.getEventFromUrl( + 'https://download.mozilla.org/?product=partner-firefox-release-smi-smi-001-latest&os=osx&lang=en-GB' + ); + expect(testEvent['product']).toBe('firefox'); + }); it('should identify product for Firefox in the App Store', function () { const testEvent = TrackProductDownload.getEventFromUrl( 'https://itunes.apple.com/app/firefox-private-safe-browser/id989804926' diff --git a/tests/unit/spec/firefox/landing/partner-build-download.js b/tests/unit/spec/firefox/landing/partner-build-download.js new file mode 100644 index 0000000000..22912f6d25 --- /dev/null +++ b/tests/unit/spec/firefox/landing/partner-build-download.js @@ -0,0 +1,265 @@ +/* + * 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/. + */ + +/* For reference read the Jasmine and Sinon docs + * Jasmine docs: https://jasmine.github.io/ + * Sinon docs: http://sinonjs.org/docs/ + */ + +import PartnerBuildDownload from '../../../../../media/js/firefox/landing/partner-build-download.es6'; + +describe('partner-build-download.es6.js', function () { + describe('init()', function () { + beforeEach(function () { + const strings = `
`; + + const button1 = `
+ +
`; + + const button2 = `
+ +
`; + + document.body.insertAdjacentHTML('beforeend', strings); + document.body.insertAdjacentHTML('beforeend', button1); + document.body.insertAdjacentHTML('beforeend', button2); + }); + + afterEach(function () { + const strings = document.getElementById('strings'); + strings.parentNode.removeChild(strings); + + const button1 = document.getElementById('download-primary'); + button1.parentNode.removeChild(button1); + + const button2 = document.getElementById('download-secondary'); + button2.parentNode.removeChild(button2); + }); + + it('should update Windows and macOS download URLs with a custom build link', function () { + PartnerBuildDownload.init(); + + const downloadLinksWin = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="win"]' + ) + ); + const downloadLinksMac = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="osx"]' + ) + ); + + downloadLinksWin.forEach((link) => + expect(link.href).toContain( + '?product=partner-firefox-release-smi-smi-001-stub' + ) + ); + downloadLinksMac.forEach((link) => + expect(link.href).toContain( + '?product=partner-firefox-release-smi-smi-001-latest' + ) + ); + }); + + it('should not update Windows URLs that are not visible on landing page', function () { + PartnerBuildDownload.init(); + + const downloadLinksWin64 = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="win64"]' + ) + ); + const downloadLinksWinMsi = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="win64-msi"]' + ) + ); + const downloadLinksWinAarch64 = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="win64-aarch64"]' + ) + ); + + downloadLinksWin64.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001-stub' + ) + ); + downloadLinksWinMsi.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001' + ) + ); + downloadLinksWinAarch64.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001' + ) + ); + }); + + it('should not update Linux download URLs with a custom build link', function () { + PartnerBuildDownload.init(); + + const downloadLinksLinux = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="linux"]' + ) + ); + const downloadLinksLinux64 = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="linux64"]' + ) + ); + + downloadLinksLinux.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001' + ) + ); + downloadLinksLinux64.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001' + ) + ); + }); + + it('should not update iOS download URLs with a custom build link', function () { + PartnerBuildDownload.init(); + + const downloadLinksIOS = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="ios"]' + ) + ); + + downloadLinksIOS.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001' + ) + ); + }); + + it('should not update Android download URLs with a custom build link', function () { + PartnerBuildDownload.init(); + + const downloadLinksAndroid = Array.from( + document.querySelectorAll( + '.download-button .download-list .download-link[data-download-version="android"]' + ) + ); + + downloadLinksAndroid.forEach((link) => + expect(link.href).not.toContain( + '?product=partner-firefox-release-smi-smi-001' + ) + ); + }); + }); +});