├── .nvmrc
├── dist
└── .gitignore
├── .eslintignore
├── .prettierrc
├── content-src
├── .eslintrc.js
├── asrouter
│ ├── docs
│ │ ├── debugging-guide.png
│ │ ├── telemetry-screenshot.png
│ │ └── targeting-guide.md
│ ├── components
│ │ ├── ConditionalWrapper
│ │ │ └── ConditionalWrapper.jsx
│ │ └── Button
│ │ │ ├── Button.jsx
│ │ │ └── _Button.scss
│ ├── template-utils.js
│ ├── templates
│ │ ├── template-manifest.jsx
│ │ ├── FirstRun
│ │ │ └── addUtmParams.js
│ │ ├── OnboardingMessage
│ │ │ ├── UpdateAction.schema.json
│ │ │ ├── ToolbarBadgeMessage.schema.json
│ │ │ └── OnboardingMessage.jsx
│ │ ├── EOYSnippet
│ │ │ └── _EOYSnippet.scss
│ │ ├── SendToDeviceSnippet
│ │ │ └── isEmailOrPhoneNumber.js
│ │ ├── FXASignupSnippet
│ │ │ └── FXASignupSnippet.jsx
│ │ └── NewsletterSnippet
│ │ │ └── NewsletterSnippet.jsx
│ ├── README.md
│ └── rich-text-strings.js
├── components
│ ├── DiscoveryStreamComponents
│ │ ├── HorizontalRule
│ │ │ ├── _HorizontalRule.scss
│ │ │ └── HorizontalRule.jsx
│ │ ├── DSPrivacyModal
│ │ │ ├── _DSPrivacyModal.scss
│ │ │ └── DSPrivacyModal.jsx
│ │ ├── DSImage
│ │ │ └── _DSImage.scss
│ │ ├── SectionTitle
│ │ │ ├── _SectionTitle.scss
│ │ │ └── SectionTitle.jsx
│ │ ├── DSLinkMenu
│ │ │ └── _DSLinkMenu.scss
│ │ ├── Highlights
│ │ │ ├── _Highlights.scss
│ │ │ └── Highlights.jsx
│ │ ├── DSMessage
│ │ │ ├── _DSMessage.scss
│ │ │ └── DSMessage.jsx
│ │ ├── Navigation
│ │ │ ├── _Navigation.scss
│ │ │ └── Navigation.jsx
│ │ ├── DSDismiss
│ │ │ └── _DSDismiss.scss
│ │ ├── CardGrid
│ │ │ └── _CardGrid.scss
│ │ ├── DSTextPromo
│ │ │ └── _DSTextPromo.scss
│ │ ├── SafeAnchor
│ │ │ └── SafeAnchor.jsx
│ │ ├── DSContextFooter
│ │ │ └── DSContextFooter.jsx
│ │ └── DSEmptyState
│ │ │ └── _DSEmptyState.scss
│ ├── DiscoveryStreamImpressionStats
│ │ └── _ImpressionStats.scss
│ ├── A11yLinkButton
│ │ ├── _A11yLinkButton.scss
│ │ └── A11yLinkButton.jsx
│ ├── Topics
│ │ ├── _Topics.scss
│ │ └── Topics.jsx
│ ├── ErrorBoundary
│ │ ├── _ErrorBoundary.scss
│ │ └── ErrorBoundary.jsx
│ ├── MoreRecommendations
│ │ ├── _MoreRecommendations.scss
│ │ └── MoreRecommendations.jsx
│ ├── Card
│ │ └── types.js
│ ├── ASRouterAdmin
│ │ └── SimpleHashRouter.jsx
│ ├── PocketLoggedInCta
│ │ ├── _PocketLoggedInCta.scss
│ │ └── PocketLoggedInCta.jsx
│ ├── TopSites
│ │ └── TopSitesConstants.js
│ ├── ConfirmDialog
│ │ └── _ConfirmDialog.scss
│ ├── DiscoveryStreamBase
│ │ └── _DiscoveryStreamBase.scss
│ ├── ContextMenu
│ │ ├── _ContextMenu.scss
│ │ └── ContextMenuButton.jsx
│ └── FluentOrText
│ │ └── FluentOrText.jsx
├── aboutlibrary
│ ├── aboutlibrary.jsx
│ └── aboutlibrary.scss
├── styles
│ ├── _normalize.scss
│ ├── activity-stream-linux.scss
│ ├── activity-stream-windows.scss
│ ├── activity-stream-mac.scss
│ └── _mixins.scss
├── lib
│ └── constants.js
└── activity-stream.jsx
├── data
└── content
│ ├── assets
│ ├── cfr_wiki_search.png
│ ├── cfr_fb_container.png
│ ├── whatsnew-send-icon.png
│ ├── cfr_enhancer_youtube.png
│ ├── cfr_google_translate.png
│ ├── cfr_pinnedtab_static.png
│ ├── illustration-gift@2x.png
│ ├── illustration-sync@2x.png
│ ├── cfr_pinnedtab_animated.png
│ ├── cfr_pinnedtab_static@2x.png
│ ├── cfr_reddit_enhancement.png
│ ├── illustration-addons@2x.png
│ ├── protection-report-icon.png
│ ├── trailhead
│ │ ├── benefit-sync.png
│ │ ├── firefox-logo.png
│ │ ├── benefit-privacy.png
│ │ ├── firefox-systems.png
│ │ ├── accounts-form-bg.jpg
│ │ ├── benefit-knowledge.png
│ │ ├── benefit-products.png
│ │ ├── card-illo-private.svg
│ │ ├── card-illo-tracking.svg
│ │ └── card-illo-sendtab.svg
│ ├── cfr_pinnedtab_animated@2x.png
│ ├── illustration-screenshots@2x.png
│ ├── cfr_pinnedtab_animated_darktheme.png
│ ├── illustration-privatebrowsing@2x.png
│ ├── cfr_pinnedtab_animated_darktheme@2x.png
│ ├── glyph-add-16.svg
│ ├── topic-show-more-12.svg
│ ├── glyph-play-12.svg
│ ├── glyph-arrowhead-down-12.svg
│ ├── glyph-arrowhead-down-16.svg
│ ├── glyph-search-16.svg
│ ├── glyph-minimize-16.svg
│ ├── glyph-dismiss-16.svg
│ ├── glyph-arrow.svg
│ ├── glyph-caret-right.svg
│ ├── glyph-info-16.svg
│ ├── glyph-maximize-16.svg
│ ├── glyph-pause-12.svg
│ ├── glyph-topsites-16.svg
│ ├── glyph-cancel-16.svg
│ ├── glyph-pocket-delete-16.svg
│ ├── glyph-pocket-16.svg
│ ├── glyph-newWindow-16.svg
│ ├── glyph-pocket-save-16.svg
│ ├── glyph-pocket-archive-16.svg
│ ├── glyph-trending-16.svg
│ ├── glyph-pin-12.svg
│ ├── glyph-open-file-16.svg
│ ├── glyph-delete-16.svg
│ ├── glyph-cfr-feature-16.svg
│ ├── glyph-star-17.svg
│ ├── glyph-edit-16.svg
│ ├── remote
│ │ └── pip-message-icon.svg
│ ├── glyph-pin-16.svg
│ ├── glyph-modal-delete-32.svg
│ ├── glyph-unpin-16.svg
│ ├── icon-removed-bookmark.svg
│ ├── glyph-webextension-16.svg
│ ├── glyph-help-24.svg
│ ├── firefox-wordmark.svg
│ ├── spinner.svg
│ └── glyph-highlights-16.svg
│ └── tippytop
│ └── images
│ ├── amazon@2x.png
│ ├── bbc-uk@2x.png
│ ├── ebay@2x.png
│ ├── ok-ru@2x.png
│ ├── olx-pl@2x.png
│ ├── vk-com@2x.png
│ ├── avito-ru@2x.png
│ ├── bing-com@2x.png
│ ├── wykop-pl@2x.png
│ ├── allegro-pl@2x.png
│ ├── baidu-com@2x.png
│ ├── google-com@2x.png
│ ├── reddit-com@2x.png
│ ├── twitter-com@2x.png
│ ├── yandex-com@2x.png
│ ├── youtube-com@2x.png
│ ├── facebook-com@2x.png
│ ├── leboncoin-fr@2x.png
│ ├── wikipedia-org@2x.png
│ ├── aliexpress-com@2x.png
│ └── duckduckgo-com@2x.png
├── test
├── browser
│ ├── red_page.html
│ ├── blue_page.html
│ ├── browser_enabled_newtabpage.js
│ ├── browser_discovery_render.js
│ ├── browser.ini
│ ├── browser_as_load_location.js
│ ├── browser_asrouter_whatsnewpanel.js
│ ├── browser_as_render.js
│ └── browser_asrouter_snippets.js
├── xpcshell
│ ├── xpcshell.ini
│ └── test_ASRouterTargeting_attribution.js
├── .eslintrc.js
└── unit
│ ├── lib
│ ├── LinksCache.test.js
│ ├── SystemTickFeed.test.js
│ └── FilterAdult.test.js
│ ├── content-src
│ └── components
│ │ ├── DiscoveryStreamComponents
│ │ ├── HorizontalRule.test.jsx
│ │ ├── SectionTitle.test.jsx
│ │ ├── Highlights.test.jsx
│ │ ├── DSPrivacyModal.test.jsx
│ │ ├── CardGrid.test.jsx
│ │ ├── DSTextPromo.test.jsx
│ │ ├── Navigation.test.jsx
│ │ ├── DSDismiss.test.jsx
│ │ └── DSMessage.test.jsx
│ │ ├── Topics.test.jsx
│ │ ├── MoreRecommendations.test.jsx
│ │ ├── addUtmParams.test.js
│ │ ├── PocketLoggedInCta.test.jsx
│ │ ├── TopSites
│ │ └── SearchShortcutsForm.test.jsx
│ │ └── FluentOrText.test.jsx
│ ├── asrouter
│ ├── schemas
│ │ └── panel
│ │ │ └── cfr-fxa-bookmark.schema.test.js
│ ├── template-utils.test.js
│ ├── compatibility-reference
│ │ └── fx57-compat.test.js
│ ├── templates
│ │ ├── Interrupt.test.jsx
│ │ └── isEmailOrPhoneNumber.test.js
│ ├── PanelTestProvider.test.js
│ └── SnippetsTestMessageProvider.test.js
│ └── common
│ └── Dedupe.test.js
├── bin
├── bootstrap
└── vendor.js
├── aboutlibrary
├── jar.mn
├── moz.build
└── content
│ └── aboutlibrary.xhtml
├── docs
├── ISSUE_TEMPLATE.md
└── v2-system-addon
│ ├── test-merges.md
│ ├── geo_locale.md
│ └── telemetry.md
├── .gitignore
├── hooks
├── post-commit
└── pre-commit
├── .mcignore
├── components.conf
├── webpack.aboutlibrary.config.js
├── CODE_OF_CONDUCT.md
├── moz.build
├── .sass-lint.yml
├── .travis.yml
├── .taskcluster.yml
├── vendor
├── PROP_TYPES_LICENSE
├── REDUX_LICENSE
├── REACT_REDUX_LICENSE
├── REACT_AND_REACT_DOM_LICENSE
└── REACT_TRANSITION_GROUP_LICENSE
├── common
└── Dedupe.jsm
├── lib
├── SystemTickFeed.jsm
├── ASRouterFeed.jsm
├── NewTabInit.jsm
└── TippyTopProvider.jsm
├── jar.mn
├── nsIAboutNewTabService.idl
├── README.md
├── loaders
└── inject-loader.js
└── mochitest.sh
/.nvmrc:
--------------------------------------------------------------------------------
1 | 8.16
2 |
--------------------------------------------------------------------------------
/dist/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | data/
2 | logs/
3 | vendor/
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "trailingComma": "es5"
5 | }
6 |
--------------------------------------------------------------------------------
/content-src/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | rules: {
3 | "import/no-commonjs": 2
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/data/content/assets/cfr_wiki_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_wiki_search.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_fb_container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_fb_container.png
--------------------------------------------------------------------------------
/data/content/assets/whatsnew-send-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/whatsnew-send-icon.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/amazon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/amazon@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/bbc-uk@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/bbc-uk@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/ebay@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/ebay@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/ok-ru@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/ok-ru@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/olx-pl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/olx-pl@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/vk-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/vk-com@2x.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_enhancer_youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_enhancer_youtube.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_google_translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_google_translate.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_pinnedtab_static.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_pinnedtab_static.png
--------------------------------------------------------------------------------
/data/content/assets/illustration-gift@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/illustration-gift@2x.png
--------------------------------------------------------------------------------
/data/content/assets/illustration-sync@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/illustration-sync@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/avito-ru@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/avito-ru@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/bing-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/bing-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/wykop-pl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/wykop-pl@2x.png
--------------------------------------------------------------------------------
/content-src/asrouter/docs/debugging-guide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/content-src/asrouter/docs/debugging-guide.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_pinnedtab_animated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_pinnedtab_animated.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_pinnedtab_static@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_pinnedtab_static@2x.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_reddit_enhancement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_reddit_enhancement.png
--------------------------------------------------------------------------------
/data/content/assets/illustration-addons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/illustration-addons@2x.png
--------------------------------------------------------------------------------
/data/content/assets/protection-report-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/protection-report-icon.png
--------------------------------------------------------------------------------
/data/content/assets/trailhead/benefit-sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/benefit-sync.png
--------------------------------------------------------------------------------
/data/content/assets/trailhead/firefox-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/firefox-logo.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/allegro-pl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/allegro-pl@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/baidu-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/baidu-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/google-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/google-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/reddit-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/reddit-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/twitter-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/twitter-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/yandex-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/yandex-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/youtube-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/youtube-com@2x.png
--------------------------------------------------------------------------------
/test/browser/red_page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/data/content/assets/cfr_pinnedtab_animated@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_pinnedtab_animated@2x.png
--------------------------------------------------------------------------------
/data/content/assets/trailhead/benefit-privacy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/benefit-privacy.png
--------------------------------------------------------------------------------
/data/content/assets/trailhead/firefox-systems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/firefox-systems.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/facebook-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/facebook-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/leboncoin-fr@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/leboncoin-fr@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/wikipedia-org@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/wikipedia-org@2x.png
--------------------------------------------------------------------------------
/test/browser/blue_page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/content-src/asrouter/docs/telemetry-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/content-src/asrouter/docs/telemetry-screenshot.png
--------------------------------------------------------------------------------
/data/content/assets/illustration-screenshots@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/illustration-screenshots@2x.png
--------------------------------------------------------------------------------
/data/content/assets/trailhead/accounts-form-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/accounts-form-bg.jpg
--------------------------------------------------------------------------------
/data/content/assets/trailhead/benefit-knowledge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/benefit-knowledge.png
--------------------------------------------------------------------------------
/data/content/assets/trailhead/benefit-products.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/trailhead/benefit-products.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/aliexpress-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/aliexpress-com@2x.png
--------------------------------------------------------------------------------
/data/content/tippytop/images/duckduckgo-com@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/tippytop/images/duckduckgo-com@2x.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_pinnedtab_animated_darktheme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_pinnedtab_animated_darktheme.png
--------------------------------------------------------------------------------
/data/content/assets/illustration-privatebrowsing@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/illustration-privatebrowsing@2x.png
--------------------------------------------------------------------------------
/data/content/assets/cfr_pinnedtab_animated_darktheme@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mozilla/activity-stream/HEAD/data/content/assets/cfr_pinnedtab_animated_darktheme@2x.png
--------------------------------------------------------------------------------
/bin/bootstrap:
--------------------------------------------------------------------------------
1 | #!/bin/sh -x
2 |
3 | # bootstrap an activity-stream repo
4 | ln -s ../../hooks/pre-commit .git/hooks/pre-commit
5 | ln -s ../../hooks/post-commit .git/hooks/post-commit
6 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/HorizontalRule/_HorizontalRule.scss:
--------------------------------------------------------------------------------
1 | .ds-hr {
2 | @include ds-border-top {
3 | border: 0;
4 | };
5 |
6 | height: 0;
7 | }
8 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamImpressionStats/_ImpressionStats.scss:
--------------------------------------------------------------------------------
1 | .impression-observer {
2 | position: absolute;
3 | top: 0;
4 | width: 100%;
5 | height: 100%;
6 | pointer-events: none;
7 | }
8 |
--------------------------------------------------------------------------------
/test/xpcshell/xpcshell.ini:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | head =
3 | firefox-appdir = browser
4 | skip-if = toolkit == 'android'
5 |
6 | [test_AboutNewTabService.js]
7 | [test_ASRouterTargeting_attribution.js]
8 | skip-if = toolkit != "cocoa" # osx specific tests
9 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/DSPrivacyModal/_DSPrivacyModal.scss:
--------------------------------------------------------------------------------
1 | .ds-privacy-modal {
2 | a:hover {
3 | text-decoration: underline;
4 | }
5 |
6 | .privacy-notice {
7 | width: 492px;
8 | padding: 40px 0;
9 | margin: auto;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/aboutlibrary/jar.mn:
--------------------------------------------------------------------------------
1 | # This Source Code Form is subject to the terms of the Mozilla Public
2 | # License, v. 2.0. If a copy of the MPL was not distributed with this
3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 | browser.jar:
5 | content/browser/ (content/*)
6 |
--------------------------------------------------------------------------------
/content-src/components/A11yLinkButton/_A11yLinkButton.scss:
--------------------------------------------------------------------------------
1 |
2 | .a11y-link-button {
3 | border: 0;
4 | padding: 0;
5 | cursor: pointer;
6 | text-align: unset;
7 | color: var(--newtab-link-primary-color);
8 |
9 | &:hover,
10 | &:focus {
11 | text-decoration: underline;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/content-src/aboutlibrary/aboutlibrary.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 | class LibraryRouter extends React.PureComponent {
5 | render() {
6 | return
;
7 | }
8 | }
9 | ReactDOM.render(, document.body);
10 |
--------------------------------------------------------------------------------
/content-src/aboutlibrary/aboutlibrary.scss:
--------------------------------------------------------------------------------
1 |
2 | .under-construction {
3 | background-image: url('chrome://browser/content/illustrations/under-construction.svg');
4 | background-repeat: no-repeat;
5 | background-position: center;
6 | min-height: 300px;
7 | min-width: 300px;
8 | margin-top: 10%;
9 | }
10 |
--------------------------------------------------------------------------------
/docs/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Please file new bugs in Bugzilla:
2 | https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=Activity%20Streams%3A%20Newtab
3 |
4 | Activity Stream is no longer accepting new issues via GitHub, but Issues are kept open, so old issues can still be viewed.
5 |
6 | Thanks for contributing!
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | .DS_Store
4 | .eslintcache
5 | *.sw[po]
6 | *.xpi
7 | *.pyc
8 | logs/
9 | dist/
10 | firefox/
11 | *.update.rdf
12 | data/content/activity-stream.bundle.js
13 | css/*.css
14 | prerendered/
15 | aboutlibrary/content/aboutlibrary.bundle.js
16 | aboutlibrary/content/*.map
17 | aboutlibrary/content/*.css
18 |
--------------------------------------------------------------------------------
/hooks/post-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Clean up any weirdness left around by prettier execution from pre-commit
4 | # hook. Can happen for some workflows (eg `git commit .`).
5 | #
6 | # Install by executing
7 | #
8 | # ln -s ../../hooks/post-commit .git/hooks/post-commit
9 | #
10 | # at the top-level of the activity-stream github repo.
11 | git update-index -g
12 |
--------------------------------------------------------------------------------
/test/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "mocha": true
4 | },
5 | "globals": {
6 | "assert": true,
7 | "chai": true,
8 | "sinon": true
9 | },
10 | "rules": {
11 | "func-name-matching": 0,
12 | "import/no-commonjs": 2,
13 | "lines-between-class-members": 0,
14 | "react/jsx-no-bind": 0,
15 | "require-await": 0
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/.mcignore:
--------------------------------------------------------------------------------
1 | npm-debug.log
2 | .DS_Store
3 | *.sw[po]
4 | *.xpi
5 | *.pyc
6 | *.update.rdf
7 | .gitignore
8 | .eslintcache
9 |
10 | /.git/
11 | /dist/
12 | /logs/
13 | /node_modules/
14 |
15 | # ignore README since it's GitHub specific
16 | /README.md
17 |
18 | # also ignores ping centre tests
19 | ping-centre/
20 |
21 | # ignore things from about:library for now
22 | aboutlibrary/
23 | content-src/aboutlibrary/
24 |
--------------------------------------------------------------------------------
/test/unit/lib/LinksCache.test.js:
--------------------------------------------------------------------------------
1 | import { LinksCache } from "lib/LinksCache.jsm";
2 |
3 | describe("LinksCache", () => {
4 | it("throws when failing request", async () => {
5 | const cache = new LinksCache();
6 |
7 | let rejected = false;
8 | try {
9 | await cache.request();
10 | } catch (error) {
11 | rejected = true;
12 | }
13 |
14 | assert(rejected);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-add-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/topic-show-more-12.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-play-12.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/components/Topics/_Topics.scss:
--------------------------------------------------------------------------------
1 | .topics {
2 | ul {
3 | margin: 0;
4 | padding: 0;
5 | @media (min-width: $break-point-large) {
6 | display: inline;
7 | padding-inline-start: 12px;
8 | }
9 | }
10 |
11 | ul li {
12 | display: inline-block;
13 |
14 | &::after {
15 | content: '•';
16 | padding: 8px;
17 | }
18 |
19 | &:last-child::after {
20 | content: none;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-arrowhead-down-12.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/aboutlibrary/moz.build:
--------------------------------------------------------------------------------
1 | # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2 | # vim: set filetype=python:
3 | # This Source Code Form is subject to the terms of the Mozilla Public
4 | # License, v. 2.0. If a copy of the MPL was not distributed with this
5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | JAR_MANIFESTS += ['jar.mn']
8 | FINAL_LIBRARY = 'browsercomps'
9 |
10 | with Files('**'):
11 | BUG_COMPONENT = ('Firefox', 'Library')
12 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | export class HorizontalRule extends React.PureComponent {
8 | render() {
9 | return
;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-arrowhead-down-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-search-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-minimize-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/styles/_normalize.scss:
--------------------------------------------------------------------------------
1 | html {
2 | box-sizing: border-box;
3 | }
4 |
5 | *,
6 | *::before,
7 | *::after {
8 | box-sizing: inherit;
9 | }
10 |
11 | *::-moz-focus-inner {
12 | border: 0;
13 | }
14 |
15 | body {
16 | margin: 0;
17 | }
18 |
19 | button,
20 | input {
21 | background-color: inherit;
22 | color: inherit;
23 | font-family: inherit;
24 | font-size: inherit;
25 | }
26 |
27 | [hidden] {
28 | display: none !important; // sass-lint:disable-line no-important
29 | }
30 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/DSImage/_DSImage.scss:
--------------------------------------------------------------------------------
1 | .ds-image {
2 | display: block;
3 | position: relative;
4 | opacity: 0;
5 |
6 | &.use-transition {
7 | transition: opacity 0.8s;
8 | }
9 |
10 | &.loaded {
11 | opacity: 1;
12 | }
13 |
14 | img,
15 | .broken-image {
16 | background-color: var(--newtab-card-placeholder-color);
17 | position: absolute;
18 | top: 0;
19 | width: 100%;
20 | height: 100%;
21 | object-fit: cover;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-dismiss-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-arrow.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | // lifted from https://gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
6 | const ConditionalWrapper = ({ condition, wrap, children }) =>
7 | condition ? wrap(children) : children;
8 |
9 | export default ConditionalWrapper;
10 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-caret-right.svg:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-info-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/styles/activity-stream-linux.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable no-css-comments
2 | /* This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 |
6 | /* This is the linux variant */
7 | // sass-lint:enable no-css-comments
8 |
9 | $os-infopanel-arrow-height: 10px;
10 | $os-infopanel-arrow-offset-end: 6px;
11 | $os-infopanel-arrow-width: 20px;
12 |
13 | @import './activity-stream';
14 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-maximize-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/styles/activity-stream-windows.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable no-css-comments
2 | /* This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 |
6 | /* This is the windows variant */
7 | // sass-lint:enable no-css-comments
8 |
9 | $os-infopanel-arrow-height: 10px;
10 | $os-infopanel-arrow-offset-end: 6px;
11 | $os-infopanel-arrow-width: 20px;
12 |
13 | @import './activity-stream';
14 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pause-12.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-topsites-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/test/unit/content-src/components/DiscoveryStreamComponents/HorizontalRule.test.jsx:
--------------------------------------------------------------------------------
1 | import { HorizontalRule } from "content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule";
2 | import React from "react";
3 | import { shallow } from "enzyme";
4 |
5 | describe("", () => {
6 | let wrapper;
7 |
8 | beforeEach(() => {
9 | wrapper = shallow();
10 | });
11 |
12 | it("should render", () => {
13 | assert.ok(wrapper.exists());
14 | assert.ok(wrapper.find(".ds-hr").exists());
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-cancel-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pocket-delete-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/SectionTitle/_SectionTitle.scss:
--------------------------------------------------------------------------------
1 | .ds-section-title {
2 | text-align: center;
3 | margin-top: 24px;
4 |
5 | .title {
6 | @include dark-theme-only {
7 | color: $white;
8 | }
9 |
10 | line-height: 48px;
11 | font-size: 36px;
12 | font-weight: 300;
13 | color: $grey-90;
14 | }
15 |
16 | .subtitle {
17 | @include dark-theme-only {
18 | color: $grey-30;
19 | }
20 |
21 | line-height: 24px;
22 | font-size: 14px;
23 | color: $grey-50;
24 | margin-top: 4px;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pocket-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-newWindow-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/components.conf:
--------------------------------------------------------------------------------
1 | # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2 | # vim: set filetype=python:
3 | # This Source Code Form is subject to the terms of the Mozilla Public
4 | # License, v. 2.0. If a copy of the MPL was not distributed with this
5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | Classes = [
8 | {
9 | 'cid': '{dfcd2adc-7867-4d3a-ba70-17501f208142}',
10 | 'contract_ids': ['@mozilla.org/browser/aboutnewtab-service;1'],
11 | 'jsm': 'resource:///modules/AboutNewTabService.jsm',
12 | 'constructor': 'AboutNewTabService',
13 | },
14 | ]
15 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pocket-save-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/styles/activity-stream-mac.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable no-css-comments
2 | /* This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 |
6 | /* This is the mac variant */
7 | // sass-lint:enable no-css-comments
8 |
9 | $os-infopanel-arrow-height: 10px;
10 | $os-infopanel-arrow-offset-end: 7px;
11 | $os-infopanel-arrow-width: 18px;
12 |
13 | [lwt-newtab-brighttext] {
14 | -moz-osx-font-smoothing: grayscale;
15 | }
16 |
17 | @import './activity-stream';
18 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pocket-archive-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-trending-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/components/ErrorBoundary/_ErrorBoundary.scss:
--------------------------------------------------------------------------------
1 | .as-error-fallback {
2 | align-items: center;
3 | border-radius: $border-radius;
4 | box-shadow: inset $inner-box-shadow;
5 | color: var(--newtab-text-conditional-color);
6 | display: flex;
7 | flex-direction: column;
8 | font-size: $error-fallback-font-size;
9 | justify-content: center;
10 | justify-items: center;
11 | line-height: $error-fallback-line-height;
12 |
13 | &.borderless-error {
14 | box-shadow: none;
15 | }
16 |
17 | a {
18 | color: var(--newtab-text-conditional-color);
19 | text-decoration: underline;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pin-12.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/webpack.aboutlibrary.config.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | const path = require("path");
6 | const config = require("./webpack.system-addon.config.js");
7 | const absolute = relPath => path.join(__dirname, relPath);
8 | module.exports = Object.assign({}, config(), {
9 | entry: absolute("content-src/aboutlibrary/aboutlibrary.jsx"),
10 | output: {
11 | path: absolute("aboutlibrary/content"),
12 | filename: "aboutlibrary.bundle.js",
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/DSLinkMenu/_DSLinkMenu.scss:
--------------------------------------------------------------------------------
1 | .ds-hero-item,
2 | .ds-list-item,
3 | .ds-card {
4 | @include context-menu-button;
5 |
6 | .context-menu {
7 | opacity: 0;
8 | }
9 |
10 | &.active {
11 | .context-menu {
12 | opacity: 1;
13 | }
14 | }
15 |
16 | &.last-item {
17 | @include context-menu-open-left;
18 |
19 | .context-menu {
20 | opacity: 1;
21 | }
22 | }
23 |
24 | &:-moz-any(:hover, :focus, .active) {
25 | @include context-menu-button-hover;
26 | outline: none;
27 |
28 | &.ds-card-grid-border {
29 | @include fade-in-card;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/content-src/components/A11yLinkButton/A11yLinkButton.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | export function A11yLinkButton(props) {
8 | // function for merging classes, if necessary
9 | let className = "a11y-link-button";
10 | if (props.className) {
11 | className += ` ${props.className}`;
12 | }
13 | return (
14 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/content-src/components/MoreRecommendations/_MoreRecommendations.scss:
--------------------------------------------------------------------------------
1 | .more-recommendations {
2 | display: flex;
3 | align-items: center;
4 | white-space: nowrap;
5 | line-height: 1.230769231; // (16 / 13) -> 16px computed
6 |
7 | &::after {
8 | background: url('#{$image-path}topic-show-more-12.svg') no-repeat center center;
9 | content: '';
10 | -moz-context-properties: fill;
11 | display: inline-block;
12 | fill: var(--newtab-link-secondary-color);
13 | height: 16px;
14 | margin-inline-start: 5px;
15 | vertical-align: top;
16 | width: 12px;
17 | }
18 |
19 | &:dir(rtl)::after {
20 | transform: scaleX(-1);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-open-file-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/asrouter/template-utils.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | export function safeURI(url) {
6 | if (!url) {
7 | return "";
8 | }
9 | const { protocol } = new URL(url);
10 | const isAllowed = [
11 | "http:",
12 | "https:",
13 | "data:",
14 | "resource:",
15 | "chrome:",
16 | ].includes(protocol);
17 | if (!isAllowed) {
18 | console.warn(`The protocol ${protocol} is not allowed for template URLs.`); // eslint-disable-line no-console
19 | }
20 | return isAllowed ? url : "";
21 | }
22 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/SectionTitle/SectionTitle.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | export class SectionTitle extends React.PureComponent {
8 | render() {
9 | const {
10 | header: { title, subtitle },
11 | } = this.props;
12 | return (
13 |
14 |
{title}
15 | {subtitle ?
{subtitle}
: null}
16 |
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-delete-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-cfr-feature-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/components/MoreRecommendations/MoreRecommendations.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | export class MoreRecommendations extends React.PureComponent {
8 | render() {
9 | const { read_more_endpoint } = this.props;
10 | if (read_more_endpoint) {
11 | return (
12 |
17 | );
18 | }
19 | return null;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-star-17.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Community Participation Guidelines
2 |
3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines.
4 | For more details, please read the
5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).
6 |
7 | ## How to Report
8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.
9 |
10 |
16 |
--------------------------------------------------------------------------------
/content-src/lib/constants.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | export const IS_NEWTAB =
6 | global.document && global.document.documentURI === "about:newtab";
7 | export const NEWTAB_DARK_THEME = {
8 | ntp_background: {
9 | r: 42,
10 | g: 42,
11 | b: 46,
12 | a: 1,
13 | },
14 | ntp_text: {
15 | r: 249,
16 | g: 249,
17 | b: 250,
18 | a: 1,
19 | },
20 | sidebar: {
21 | r: 56,
22 | g: 56,
23 | b: 61,
24 | a: 1,
25 | },
26 | sidebar_text: {
27 | r: 249,
28 | g: 249,
29 | b: 250,
30 | a: 1,
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-edit-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/test/unit/content-src/components/DiscoveryStreamComponents/SectionTitle.test.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { SectionTitle } from "content-src/components/DiscoveryStreamComponents/SectionTitle/SectionTitle";
3 | import { shallow } from "enzyme";
4 |
5 | describe("", () => {
6 | let wrapper;
7 |
8 | beforeEach(() => {
9 | wrapper = shallow();
10 | });
11 |
12 | it("should render", () => {
13 | assert.ok(wrapper.exists());
14 | assert.ok(wrapper.find(".ds-section-title").exists());
15 | });
16 |
17 | it("should render a subtitle", () => {
18 | wrapper.setProps({ header: { title: "Foo", subtitle: "Bar" } });
19 |
20 | assert.equal(wrapper.find(".subtitle").text(), "Bar");
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/data/content/assets/remote/pip-message-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-pin-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/test/browser/browser_enabled_newtabpage.js:
--------------------------------------------------------------------------------
1 | function checkSpec(uri, check, message) {
2 | const { spec } = NetUtil.newChannel({
3 | loadUsingSystemPrincipal: true,
4 | uri,
5 | }).URI;
6 |
7 | info(`got ${spec} for ${uri}`);
8 | check(spec, "about:blank", message);
9 | }
10 |
11 | add_task(async function test_newtab_enabled() {
12 | checkSpec(
13 | "about:newtab",
14 | isnot,
15 | "did not get blank for default about:newtab"
16 | );
17 | checkSpec("about:home", isnot, "did not get blank for default about:home");
18 |
19 | await SpecialPowers.pushPrefEnv({
20 | set: [["browser.newtabpage.enabled", false]],
21 | });
22 |
23 | checkSpec("about:newtab", is, "got blank when newtab is not enabled");
24 | checkSpec("about:home", isnot, "still did not get blank for about:home");
25 | });
26 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-modal-delete-32.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-unpin-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/test/unit/content-src/components/Topics.test.jsx:
--------------------------------------------------------------------------------
1 | import { Topic, Topics } from "content-src/components/Topics/Topics";
2 | import React from "react";
3 | import { shallow } from "enzyme";
4 |
5 | describe("", () => {
6 | it("should render a Topics element", () => {
7 | const wrapper = shallow();
8 | assert.ok(wrapper.exists());
9 | });
10 | it("should render a Topic element for each topic with the right url", () => {
11 | const data = [
12 | { name: "topic1", url: "https://topic1.com" },
13 | { name: "topic2", url: "https://topic2.com" },
14 | ];
15 |
16 | const wrapper = shallow();
17 |
18 | const topics = wrapper.find(Topic);
19 | assert.lengthOf(topics, 2);
20 | topics.forEach((topic, i) => assert.equal(topic.props().url, data[i].url));
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/moz.build:
--------------------------------------------------------------------------------
1 | # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2 | # vim: set filetype=python:
3 | # This Source Code Form is subject to the terms of the Mozilla Public
4 | # License, v. 2.0. If a copy of the MPL was not distributed with this
5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | with Files("**"):
8 | BUG_COMPONENT = ("Firefox", "New Tab Page")
9 |
10 | BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
11 |
12 | SPHINX_TREES['docs'] = 'docs'
13 |
14 | XPCSHELL_TESTS_MANIFESTS += [
15 | 'test/xpcshell/xpcshell.ini',
16 | ]
17 |
18 | XPIDL_SOURCES += [
19 | 'nsIAboutNewTabService.idl',
20 | ]
21 |
22 | XPIDL_MODULE = 'browser-newtab'
23 |
24 | EXTRA_JS_MODULES += [
25 | 'AboutNewTabService.jsm',
26 | ]
27 |
28 | XPCOM_MANIFESTS += [
29 | 'components.conf',
30 | ]
31 |
32 | JAR_MANIFESTS += ['jar.mn']
33 |
--------------------------------------------------------------------------------
/data/content/assets/icon-removed-bookmark.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.sass-lint.yml:
--------------------------------------------------------------------------------
1 | options:
2 | merge-default-rules: true
3 | max-warnings: 0
4 |
5 | files:
6 | include: 'content-src/**/*.scss'
7 |
8 | rules:
9 | class-name-format: 0
10 | extends-before-declarations: 2
11 | extends-before-mixins: 2
12 | force-element-nesting: 0
13 | force-pseudo-nesting: 0
14 | hex-notation: [2, {style: uppercase}]
15 | indentation: [2, {size: 2}]
16 | leading-zero: [2, {include: true}]
17 | mixins-before-declarations: [2, {exclude: [breakpoint, mq]}]
18 | nesting-depth: [2, {max-depth: 4}]
19 | no-debug: 1
20 | no-disallowed-properties: [1, {properties: [margin-left, margin-right, text-transform]}]
21 | no-duplicate-properties: 2
22 | no-misspelled-properties: [2, {extra-properties: [-moz-context-properties]}]
23 | no-url-domains: 0
24 | no-vendor-prefixes: 0
25 | no-warn: 1
26 | placeholder-in-extend: 2
27 | property-sort-order: 0
28 |
--------------------------------------------------------------------------------
/content-src/components/Card/types.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | export const cardContextTypes = {
6 | history: {
7 | fluentID: "newtab-label-visited",
8 | icon: "history-item",
9 | },
10 | removedBookmark: {
11 | fluentID: "newtab-label-removed-bookmark",
12 | icon: "bookmark-removed",
13 | },
14 | bookmark: {
15 | fluentID: "newtab-label-bookmarked",
16 | icon: "bookmark-added",
17 | },
18 | trending: {
19 | fluentID: "newtab-label-recommended",
20 | icon: "trending",
21 | },
22 | pocket: {
23 | fluentID: "newtab-label-saved",
24 | icon: "pocket",
25 | },
26 | download: {
27 | fluentID: "newtab-label-download",
28 | icon: "download",
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-webextension-16.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/Highlights/_Highlights.scss:
--------------------------------------------------------------------------------
1 | .ds-highlights {
2 | .section {
3 | margin: 0 (-$section-horizontal-padding);
4 |
5 | .section-list {
6 | grid-gap: var(--gridRowGap);
7 | grid-template-columns: repeat(4, 1fr);
8 |
9 | .card-outer {
10 | $line-height: 20px;
11 | height: 175px;
12 |
13 | .card-host-name {
14 | font-size: 13px;
15 | line-height: $line-height;
16 | margin-bottom: 2px;
17 | padding-bottom: 0;
18 | text-transform: unset; // sass-lint:disable-line no-disallowed-properties
19 | }
20 |
21 | .card-title {
22 | font-size: 14px;
23 | font-weight: 600;
24 | line-height: $line-height;
25 | max-height: $line-height;
26 | }
27 | }
28 | }
29 | }
30 |
31 | .hide-for-narrow {
32 | display: block;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/browser/browser_discovery_render.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | async function before({ pushPrefs }) {
4 | await pushPrefs([
5 | "browser.newtabpage.activity-stream.discoverystream.config",
6 | JSON.stringify({
7 | collapsible: true,
8 | enabled: true,
9 | hardcoded_layout: true,
10 | }),
11 | ]);
12 | }
13 |
14 | test_newtab({
15 | before,
16 | test: async function test_render_hardcoded() {
17 | const topSites = await ContentTaskUtils.waitForCondition(() =>
18 | content.document.querySelector(".ds-top-sites")
19 | );
20 | ok(topSites, "Got the discovery stream top sites section");
21 |
22 | const learnMore = content.document.querySelector(
23 | ".ds-layout a[href$=new_tab_learn_more]"
24 | );
25 | is(
26 | learnMore.textContent,
27 | "What’s Pocket?",
28 | "Got the rendered Message with link text and url within discovery stream"
29 | );
30 | },
31 | });
32 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/Highlights/Highlights.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import { connect } from "react-redux";
6 | import React from "react";
7 | import { SectionIntl } from "content-src/components/Sections/Sections";
8 |
9 | export class _Highlights extends React.PureComponent {
10 | render() {
11 | const section = this.props.Sections.find(s => s.id === "highlights");
12 | if (!section || !section.enabled) {
13 | return null;
14 | }
15 |
16 | return (
17 |
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export const Highlights = connect(state => ({ Sections: state.Sections }))(
25 | _Highlights
26 | );
27 |
--------------------------------------------------------------------------------
/test/unit/asrouter/schemas/panel/cfr-fxa-bookmark.schema.test.js:
--------------------------------------------------------------------------------
1 | import schema from "content-src/asrouter/schemas/panel/cfr-fxa-bookmark.schema.json";
2 |
3 | const DEFAULT_CONTENT = {
4 | title: "Sync your bookmarks everywhere",
5 | text: "Great find! Now don't be left without this bookmark.",
6 | cta: "Sync bookmarks now",
7 | info_icon: {
8 | tooltiptext: "Learn more",
9 | },
10 | };
11 |
12 | const L10N_CONTENT = {
13 | title: { string_id: "cfr-bookmark-title" },
14 | text: { string_id: "cfr-bookmark-body" },
15 | cta: { string_id: "cfr-bookmark-link-text" },
16 | info_icon: {
17 | tooltiptext: { string_id: "cfr-bookmark-tooltip-text" },
18 | },
19 | };
20 |
21 | describe("CFR FxA Message Schema", () => {
22 | it("should validate DEFAULT_CONTENT", () => {
23 | assert.jsonSchema(DEFAULT_CONTENT, schema);
24 | });
25 | it("should validate L10N_CONTENT", () => {
26 | assert.jsonSchema(L10N_CONTENT, schema);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | # when changing this, be sure to edit .nvrmc and package.json too
5 | - 8
6 |
7 | python:
8 | - "2.7"
9 |
10 | addons:
11 | # Run unit tests in Nightly to be in line with what Firefox tests would run against
12 | firefox: "latest-nightly"
13 |
14 | cache:
15 | directories:
16 | - node_modules
17 |
18 | before_install:
19 | # see https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
20 | - "export DISPLAY=:99.0"
21 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 -extension RANDR"
22 | - export PATH="$PATH:$HOME/.rvm/bin"
23 | - export PATH="$PATH:./node_modules/.bin"
24 | - sleep 3
25 |
26 | install:
27 | - npm config set spin false
28 | - npm install
29 |
30 | script:
31 | - npm test
32 |
33 | notifications:
34 | email: false
35 |
--------------------------------------------------------------------------------
/content-src/components/Topics/Topics.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | export class Topic extends React.PureComponent {
8 | render() {
9 | const { url, name } = this.props;
10 | return (
11 |
12 |
13 | {name}
14 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export class Topics extends React.PureComponent {
21 | render() {
22 | const { topics } = this.props;
23 | return (
24 |
25 |
26 |
27 | {topics &&
28 | topics.map(t => )}
29 |
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/DSMessage/_DSMessage.scss:
--------------------------------------------------------------------------------
1 | .ds-message {
2 | margin: 8px 0 0;
3 |
4 | .title {
5 | display: flex;
6 | align-items: center;
7 |
8 | .glyph {
9 | @include dark-theme-only {
10 | fill: $grey-30;
11 | }
12 |
13 | width: 16px;
14 | height: 16px;
15 | margin: 0 6px 0 0;
16 | -moz-context-properties: fill;
17 | fill: $grey-50;
18 | background-position: center center;
19 | background-size: 16px;
20 | background-repeat: no-repeat;
21 | }
22 |
23 | .title-text {
24 | @include dark-theme-only {
25 | color: $grey-30;
26 | }
27 |
28 | line-height: 20px;
29 | font-size: 13px;
30 | color: $grey-50;
31 | font-weight: 600;
32 | padding-right: 12px;
33 | }
34 |
35 | .link {
36 | line-height: 20px;
37 | font-size: 13px;
38 |
39 | &:hover,
40 | &:focus {
41 | text-decoration: underline;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/content-src/asrouter/components/Button/Button.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | const ALLOWED_STYLE_TAGS = ["color", "backgroundColor"];
8 |
9 | export const Button = props => {
10 | const style = {};
11 |
12 | // Add allowed style tags from props, e.g. props.color becomes style={color: props.color}
13 | for (const tag of ALLOWED_STYLE_TAGS) {
14 | if (typeof props[tag] !== "undefined") {
15 | style[tag] = props[tag];
16 | }
17 | }
18 | // remove border if bg is set to something custom
19 | if (style.backgroundColor) {
20 | style.border = "0";
21 | }
22 |
23 | return (
24 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/data/content/assets/glyph-help-24.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/test/unit/content-src/components/MoreRecommendations.test.jsx:
--------------------------------------------------------------------------------
1 | import { MoreRecommendations } from "content-src/components/MoreRecommendations/MoreRecommendations";
2 | import React from "react";
3 | import { shallow } from "enzyme";
4 |
5 | describe("", () => {
6 | it("should render a MoreRecommendations element", () => {
7 | const wrapper = shallow();
8 | assert.ok(wrapper.exists());
9 | });
10 | it("should render a link when provided with read_more_endpoint prop", () => {
11 | const wrapper = shallow(
12 |
13 | );
14 |
15 | const link = wrapper.find(".more-recommendations");
16 | assert.lengthOf(link, 1);
17 | });
18 | it("should not render a link when provided with read_more_endpoint prop", () => {
19 | const wrapper = shallow();
20 |
21 | const link = wrapper.find(".more-recommendations");
22 | assert.lengthOf(link, 0);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/unit/asrouter/template-utils.test.js:
--------------------------------------------------------------------------------
1 | import { safeURI } from "content-src/asrouter/template-utils";
2 |
3 | describe("safeURI", () => {
4 | let warnStub;
5 | beforeEach(() => {
6 | warnStub = sinon.stub(console, "warn");
7 | });
8 | afterEach(() => {
9 | warnStub.restore();
10 | });
11 | it("should allow http: URIs", () => {
12 | assert.equal(safeURI("http://foo.com"), "http://foo.com");
13 | });
14 | it("should allow https: URIs", () => {
15 | assert.equal(safeURI("https://foo.com"), "https://foo.com");
16 | });
17 | it("should allow data URIs", () => {
18 | assert.equal(
19 | safeURI("data:image/png;base64,iVBO"),
20 | "data:image/png;base64,iVBO"
21 | );
22 | });
23 | it("should not allow javascript: URIs", () => {
24 | assert.equal(safeURI("javascript:foo()"), ""); // eslint-disable-line no-script-url
25 | assert.calledOnce(warnStub);
26 | });
27 | it("should not warn if the URL is falsey ", () => {
28 | assert.equal(safeURI(), "");
29 | assert.notCalled(warnStub);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/content-src/components/DiscoveryStreamComponents/Navigation/_Navigation.scss:
--------------------------------------------------------------------------------
1 | .ds-navigation {
2 | line-height: 32px;
3 | padding: 4px 0;
4 | font-size: 14px;
5 | font-weight: 600;
6 |
7 | &.ds-navigation-centered {
8 | text-align: center;
9 | }
10 |
11 | &.ds-navigation-right-aligned {
12 | text-align: end;
13 | }
14 |
15 | ul {
16 | margin: 0;
17 | padding: 0;
18 | }
19 |
20 | ul li {
21 | display: inline-block;
22 |
23 | &::after {
24 | content: '·';
25 | padding: 8px;
26 | color: $grey-50;
27 | }
28 |
29 | &:last-child::after {
30 | content: none;
31 | }
32 |
33 | a {
34 | &:hover {
35 | // text-decoration: underline; didn't quite match comps.
36 | border-bottom: 1px solid var(--newtab-link-primary-color);
37 |
38 | &:active {
39 | border-bottom: 1px solid $blue-70;
40 | }
41 | }
42 |
43 | &:active {
44 | color: $blue-70;
45 | }
46 | }
47 | }
48 |
49 | .ds-header {
50 | margin-bottom: 8px;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/data/content/assets/firefox-wordmark.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/content-src/asrouter/templates/template-manifest.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import { EOYSnippet } from "./EOYSnippet/EOYSnippet";
6 | import { FXASignupSnippet } from "./FXASignupSnippet/FXASignupSnippet";
7 | import { NewsletterSnippet } from "./NewsletterSnippet/NewsletterSnippet";
8 | import { SendToDeviceSnippet } from "./SendToDeviceSnippet/SendToDeviceSnippet";
9 | import { SimpleBelowSearchSnippet } from "./SimpleBelowSearchSnippet/SimpleBelowSearchSnippet";
10 | import { SimpleSnippet } from "./SimpleSnippet/SimpleSnippet";
11 |
12 | // Key names matching schema name of templates
13 | export const SnippetsTemplates = {
14 | simple_snippet: SimpleSnippet,
15 | newsletter_snippet: NewsletterSnippet,
16 | fxa_signup_snippet: FXASignupSnippet,
17 | send_to_device_snippet: SendToDeviceSnippet,
18 | eoy_snippet: EOYSnippet,
19 | simple_below_search_snippet: SimpleBelowSearchSnippet,
20 | };
21 |
--------------------------------------------------------------------------------
/.taskcluster.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | policy:
3 | pullRequests: public
4 | tasks:
5 | $if: 'tasks_for in ["github-push", "github-pull-request"]'
6 | then:
7 | $let:
8 | repo_url:
9 | $if: 'tasks_for == "github-push"'
10 | then: ${event.repository.clone_url}
11 | else: ${event.pull_request.head.repo.clone_url}
12 | ref:
13 | $if: 'tasks_for == "github-push"'
14 | then: ${event.after}
15 | else: ${event.pull_request.head.sha}
16 | in:
17 | - provisionerId: proj-misc
18 | workerType: ci
19 | deadline: ${fromNow('1 day')}
20 | payload:
21 | maxRunTime: 7200
22 | image: piatra/asmochitests
23 | command:
24 | - /bin/bash
25 | - '--login'
26 | - '-c'
27 | - >-
28 | git clone ${repo_url} /activity-stream && cd /activity-stream &&
29 | git checkout ${ref} && bash ./mochitest.sh
30 | metadata:
31 | name: activitystream
32 | description: run mochitests for PRs
33 | owner: noreply@mozilla.com
34 | source: ${repo_url}
35 |
--------------------------------------------------------------------------------
/content-src/components/ASRouterAdmin/SimpleHashRouter.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import React from "react";
6 |
7 | export class SimpleHashRouter extends React.PureComponent {
8 | constructor(props) {
9 | super(props);
10 | this.onHashChange = this.onHashChange.bind(this);
11 | this.state = { hash: global.location.hash };
12 | }
13 |
14 | onHashChange() {
15 | this.setState({ hash: global.location.hash });
16 | }
17 |
18 | componentWillMount() {
19 | global.addEventListener("hashchange", this.onHashChange);
20 | }
21 |
22 | componentWillUnmount() {
23 | global.removeEventListener("hashchange", this.onHashChange);
24 | }
25 |
26 | render() {
27 | const [, ...routes] = this.state.hash.split("-");
28 | return React.cloneElement(this.props.children, {
29 | location: {
30 | hash: this.state.hash,
31 | routes,
32 | },
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/content-src/components/PocketLoggedInCta/_PocketLoggedInCta.scss:
--------------------------------------------------------------------------------
1 | .pocket-logged-in-cta {
2 | $max-button-width: 130px;
3 | $min-button-height: 18px;
4 | font-size: 13px;
5 | margin-inline-end: 20px;
6 | display: flex;
7 | align-items: flex-start;
8 |
9 | .pocket-cta-button {
10 | white-space: nowrap;
11 | background: $blue-60;
12 | letter-spacing: -0.34px;
13 | color: $white;
14 | border-radius: 4px;
15 | cursor: pointer;
16 | max-width: $max-button-width;
17 | // The button height is 2px taller than the rest of the cta text.
18 | // So I move it up by 1px to align with the rest of the cta text.
19 | margin-top: -1px;
20 | min-height: $min-button-height;
21 | padding: 0 8px;
22 | display: inline-flex;
23 | justify-content: center;
24 | align-items: center;
25 | font-size: 11px;
26 | margin-inline-end: 10px;
27 | }
28 |
29 | .cta-text {
30 | font-weight: normal;
31 | font-size: 13px;
32 | line-height: 1.230769231; // (16 / 13) –> 16px computed
33 | }
34 |
35 | .pocket-cta-button,
36 | .cta-text {
37 | vertical-align: top;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/content-src/asrouter/docs/targeting-guide.md:
--------------------------------------------------------------------------------
1 | # Guide to targeting with JEXL
2 |
3 | For a more in-depth explanation of JEXL syntax you can read the [Normady project docs](https://mozilla.github.io/normandy/user/filters.html?highlight=jexl).
4 |
5 | ### How to write JEXL targeting expressions
6 | A message needs to contain the `targeting` property (JEXL string) which is evaluated against the provided attributes.
7 | Examples:
8 |
9 | ```javascript
10 | {
11 | "id": "7864",
12 | "content": {...},
13 | // simple equality check
14 | "targeting": "usesFirefoxSync == true"
15 | }
16 |
17 | {
18 | "id": "7865",
19 | "content": {...},
20 | // using JEXL transforms and combining two attributes
21 | "targeting": "usesFirefoxSync == true && profileAgeCreated > '2018-01-07'|date"
22 | }
23 |
24 | {
25 | "id": "7866",
26 | "content": {...},
27 | // targeting addon information
28 | "targeting": "addonsInfo.addons['activity-stream@mozilla.org'].name == 'Activity Stream'"
29 | }
30 |
31 | {
32 | "id": "7866",
33 | "content": {...},
34 | // targeting based on time
35 | "targeting": "currentDate > '2018-08-08'|date"
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/content-src/asrouter/templates/FirstRun/addUtmParams.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | /**
6 | * BASE_PARAMS keys/values can be modified from outside this file
7 | */
8 | export const BASE_PARAMS = {
9 | utm_source: "activity-stream",
10 | utm_campaign: "firstrun",
11 | utm_medium: "referral",
12 | };
13 |
14 | /**
15 | * Takes in a url as a string or URL object and returns a URL object with the
16 | * utm_* parameters added to it. If a URL object is passed in, the paraemeters
17 | * are added to it (the return value can be ignored in that case as it's the
18 | * same object).
19 | */
20 | export function addUtmParams(url, utmTerm) {
21 | let returnUrl = url;
22 | if (typeof returnUrl === "string") {
23 | returnUrl = new URL(url);
24 | }
25 | Object.keys(BASE_PARAMS).forEach(key => {
26 | returnUrl.searchParams.append(key, BASE_PARAMS[key]);
27 | });
28 | returnUrl.searchParams.append("utm_term", utmTerm);
29 | return returnUrl;
30 | }
31 |
--------------------------------------------------------------------------------
/test/unit/content-src/components/addUtmParams.test.js:
--------------------------------------------------------------------------------
1 | import {
2 | addUtmParams,
3 | BASE_PARAMS,
4 | } from "content-src/asrouter/templates/FirstRun/addUtmParams";
5 |
6 | describe("addUtmParams", () => {
7 | it("should convert a string URL", () => {
8 | const result = addUtmParams("https://foo.com", "foo");
9 | assert.equal(result.hostname, "foo.com");
10 | });
11 | it("should add all base params", () => {
12 | assert.match(
13 | addUtmParams(new URL("https://foo.com"), "foo").toString(),
14 | /utm_source=activity-stream&utm_campaign=firstrun&utm_medium=referral/
15 | );
16 | });
17 | it("should allow updating base params utm values", () => {
18 | BASE_PARAMS.utm_campaign = "firstrun-default";
19 | assert.match(
20 | addUtmParams(new URL("https://foo.com"), "foo", "default").toString(),
21 | /utm_source=activity-stream&utm_campaign=firstrun-default&utm_medium=referral/
22 | );
23 | });
24 | it("should add utm_term", () => {
25 | const params = addUtmParams(new URL("https://foo.com"), "foo").searchParams;
26 | assert.equal(params.get("utm_term"), "foo", "utm_term");
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/vendor/PROP_TYPES_LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2013-present, Facebook, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/REDUX_LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-present Dan Abramov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/REACT_REDUX_LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-present Dan Abramov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/unit/asrouter/compatibility-reference/fx57-compat.test.js:
--------------------------------------------------------------------------------
1 | import EOYSnippetSchema from "content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json";
2 | import { expectedValues } from "./snippets-fx57";
3 | import SimpleSnippetSchema from "content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json";
4 | import SubmitFormSchema from "content-src/asrouter/templates/SubmitFormSnippet/SubmitFormSnippet.schema.json";
5 |
6 | export const SnippetsSchemas = {
7 | eoy_snippet: EOYSnippetSchema,
8 | simple_snippet: SimpleSnippetSchema,
9 | newsletter_snippet: SubmitFormSchema,
10 | fxa_signup_snippet: SubmitFormSchema,
11 | send_to_device_snippet: SubmitFormSchema,
12 | };
13 |
14 | describe("Firefox 57 compatibility test", () => {
15 | Object.keys(expectedValues).forEach(template => {
16 | describe(template, () => {
17 | const schema = SnippetsSchemas[template];
18 | it(`should have a schema for ${template}`, () => {
19 | assert.ok(schema);
20 | });
21 | it(`should validate with the schema for ${template}`, () => {
22 | assert.jsonSchema(expectedValues[template], schema);
23 | });
24 | });
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/vendor/REACT_AND_REACT_DOM_LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Facebook, Inc. and its affiliates.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/hooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Recommended pre-commit git hook for activity-stream github repo
4 | #
5 | # Install by executing
6 | #
7 | # ln -s ../../hooks/pre-commit .git/hooks/pre-commit
8 | #
9 | # at the top-level of the activity-stream github repo.
10 | #
11 | # Runs `eslint --fix` on all selected files, which, given our current
12 | # prettier configuration, means prettifying these files as well. The
13 | # commit will be aborted if eslint exits with a failure code.
14 | #
15 | # Based on the example script in the prettier docs at
16 | # https://prettier.io/docs/en/precommit.html
17 |
18 | FILES=$(git diff --cached --name-only --diff-filter=ACM "*.js" "*.jsx" "*.jsm" | sed 's| |\\ |g')
19 | [ -z "$FILES" ] && exit 0
20 |
21 | echo "$FILES" | xargs ./node_modules/.bin/eslint --cache --fix
22 | if [ $? -ne 0 ]
23 | then
24 | echo "eslint found errors but was unable to fix them all with --fix."
25 | echo "Please check the output, resolve any issues, and retry."
26 | echo "If you want to commit anyway, pass the --no-verify flag to git commit."
27 | exit -1
28 | fi
29 |
30 | # Add back the modified/prettified files to staging
31 | echo "$FILES" | xargs git add
32 |
33 | exit 0
34 |
--------------------------------------------------------------------------------
/content-src/activity-stream.jsx:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | import { actionCreators as ac, actionTypes as at } from "common/Actions.jsm";
6 | import { Base } from "content-src/components/Base/Base";
7 | import { DetectUserSessionStart } from "content-src/lib/detect-user-session-start";
8 | import { initStore } from "content-src/lib/init-store";
9 | import { Provider } from "react-redux";
10 | import React from "react";
11 | import ReactDOM from "react-dom";
12 | import { reducers } from "common/Reducers.jsm";
13 |
14 | const store = initStore(reducers);
15 |
16 | new DetectUserSessionStart(store).sendEventOrAddListener();
17 |
18 | store.dispatch(ac.AlsoToMain({ type: at.NEW_TAB_STATE_REQUEST }));
19 |
20 | ReactDOM.hydrate(
21 |
22 |
27 | ,
28 | document.getElementById("root")
29 | );
30 |
--------------------------------------------------------------------------------
/test/browser/browser.ini:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | support-files =
3 | blue_page.html
4 | red_page.html
5 | head.js
6 | prefs =
7 | browser.newtabpage.activity-stream.debug=false
8 | browser.newtabpage.activity-stream.discoverystream.enabled=true
9 | browser.newtabpage.activity-stream.discoverystream.endpoints=data:
10 | browser.newtabpage.activity-stream.feeds.section.topstories=true
11 | browser.newtabpage.activity-stream.feeds.section.topstories.options={"provider_name":""}
12 |
13 | [browser_aboutwelcome.js]
14 | [browser_as_load_location.js]
15 | [browser_as_render.js]
16 | [browser_asrouter_snippets.js]
17 | [browser_asrouter_targeting.js]
18 | [browser_asrouter_trigger_listeners.js]
19 | [browser_discovery_render.js]
20 | [browser_discovery_styles.js]
21 | [browser_enabled_newtabpage.js]
22 | [browser_highlights_section.js]
23 | [browser_getScreenshots.js]
24 | [browser_newtab_overrides.js]
25 | [browser_onboarding_rtamo.js]
26 | skip-if = (os == "linux") # Test setup only implemented for OSX and Windows
27 | [browser_topsites_contextMenu_options.js]
28 | [browser_topsites_section.js]
29 | [browser_asrouter_cfr.js]
30 | [browser_asrouter_bookmarkpanel.js]
31 | [browser_asrouter_toolbarbadge.js]
32 | [browser_asrouter_whatsnewpanel.js]
33 |
--------------------------------------------------------------------------------
/test/unit/common/Dedupe.test.js:
--------------------------------------------------------------------------------
1 | import { Dedupe } from "common/Dedupe.jsm";
2 |
3 | describe("Dedupe", () => {
4 | let instance;
5 | beforeEach(() => {
6 | instance = new Dedupe();
7 | });
8 | describe("group", () => {
9 | it("should remove duplicates inside the groups", () => {
10 | const beforeItems = [[1, 1, 1], [2, 2, 2], [3, 3, 3]];
11 | const afterItems = [[1], [2], [3]];
12 | assert.deepEqual(instance.group(...beforeItems), afterItems);
13 | });
14 | it("should remove duplicates between groups, favouring earlier groups", () => {
15 | const beforeItems = [[1, 2, 3], [2, 3, 4], [3, 4, 5]];
16 | const afterItems = [[1, 2, 3], [4], [5]];
17 | assert.deepEqual(instance.group(...beforeItems), afterItems);
18 | });
19 | it("should remove duplicates from groups of objects", () => {
20 | instance = new Dedupe(item => item.id);
21 | const beforeItems = [
22 | [{ id: 1 }, { id: 1 }, { id: 2 }],
23 | [{ id: 1 }, { id: 3 }, { id: 2 }],
24 | [{ id: 1 }, { id: 2 }, { id: 5 }],
25 | ];
26 | const afterItems = [[{ id: 1 }, { id: 2 }], [{ id: 3 }], [{ id: 5 }]];
27 | assert.deepEqual(instance.group(...beforeItems), afterItems);
28 | });
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/content-src/asrouter/templates/OnboardingMessage/UpdateAction.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "UpdateActionMessage",
3 | "description": "A template for messages that execute predetermined actions.",
4 | "version": "1.0.0",
5 | "type": "object",
6 | "properties": {
7 | "action": {
8 | "type": "object",
9 | "properties": {
10 | "id": {
11 | "type": "string"
12 | },
13 | "data": {
14 | "type": "object",
15 | "properties": {
16 | "url": {
17 | "type": "string",
18 | "description": "URL data to be used as argument to the action"
19 | },
20 | "expireDelta": {
21 | "type": "number",
22 | "description": "Expiration timestamp to be used as argument to the action"
23 | }
24 | }
25 | },
26 | "description": "Additional data provided as argument when executing the action"
27 | },
28 | "additionalProperties": false,
29 | "description": "Optional action to take in addition to showing the notification"
30 | },
31 | "additionalProperties": false,
32 | "required": ["id", "action"]
33 | },
34 | "additionalProperties": false,
35 | "required": ["action"]
36 | }
37 |
--------------------------------------------------------------------------------
/content-src/components/TopSites/TopSitesConstants.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | export const TOP_SITES_SOURCE = "TOP_SITES";
6 | export const TOP_SITES_CONTEXT_MENU_OPTIONS = [
7 | "CheckPinTopSite",
8 | "EditTopSite",
9 | "Separator",
10 | "OpenInNewWindow",
11 | "OpenInPrivateWindow",
12 | "Separator",
13 | "BlockUrl",
14 | "DeleteUrl",
15 | ];
16 | export const TOP_SITES_SPOC_CONTEXT_MENU_OPTIONS = [
17 | "PinSpocTopSite",
18 | "Separator",
19 | "OpenInNewWindow",
20 | "OpenInPrivateWindow",
21 | "Separator",
22 | "BlockUrl",
23 | "ShowPrivacyInfo",
24 | ];
25 | // the special top site for search shortcut experiment can only have the option to unpin (which removes) the topsite
26 | export const TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS = [
27 | "CheckPinTopSite",
28 | "Separator",
29 | "BlockUrl",
30 | ];
31 | // minimum size necessary to show a rich icon instead of a screenshot
32 | export const MIN_RICH_FAVICON_SIZE = 96;
33 | // minimum size necessary to show any icon in the top left corner with a screenshot
34 | export const MIN_CORNER_FAVICON_SIZE = 16;
35 |
--------------------------------------------------------------------------------
/data/content/assets/spinner.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/docs/v2-system-addon/test-merges.md:
--------------------------------------------------------------------------------
1 | ## bin/test-merges.js documentation
2 |
3 | A script intended to be run from cron regularly. It notices when a new PR has been merged to github, and then exports the code to a copy of mozilla-central and pushes it to pine, so that all the tests can be run. It annotates the PR with the link to treeherder with the test results.
4 |
5 | Setup, needs to happen before first run:
6 |
7 | Ensure that mozilla/activity-stream has a label called pushed-to-pine.
8 |
9 | ```bash
10 | # mkdir /home/monkey/as-pine-testing
11 | # cd /home/monkey/as-pine-testing
12 | # git clone https://github.com/mozilla/activity-stream.git
13 | # npm install
14 | ```
15 |
16 | Example usage:
17 |
18 | ```bash
19 | AS_PINE_TOKEN=01234567890 \
20 | AS_PINE_TEST_DIR=/home/monkey/as-pine-testing \
21 | node bin/test-merges.js
22 | ```
23 |
24 | AS_PINE_TOKEN is a github token for accessing mozilla/activity-stream. We use a token from the github user that has access to the mozilla/activity-stream repo (in order to label issues), and nothing else.
25 |
26 | AS_PINE_TEST_DIR should be a single directory which will contain local copies of both the activity-stream github repo and mozilla-central. It's highly advised that AS_PINE_TEST_DIR be used for nothing else, to avoid accidentally clobbering real work.
27 |
--------------------------------------------------------------------------------
/aboutlibrary/content/aboutlibrary.xhtml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 | Library
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |