Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const lazy = {};
import { actionTypes as at } from "resource://newtab/common/Actions.mjs";
ChromeUtils.defineESModuleGetters(lazy, {
NewTabAttributionService:
});
const PREF_SYSTEM_ATTRIBUTION = "discoverystream.attribution.enabled";
const PREF_UNIFIED_ADS_SPOCS_ENABLED = "unifiedAds.spocs.enabled";
const PREF_UNIFIED_ADS_TILES_ENABLED = "unifiedAds.tiles.enabled";
// topsites
const PREF_FEED_TOPSITES = "feeds.topsites";
const PREF_SYSTEM_TOPSITES = "feeds.system.topsites";
const PREF_SHOW_SPONSORED_TOPSITES = "showSponsoredTopSites";
// spocs
const PREF_FEED_SECTION_TOPSTORIES = "feeds.section.topstories";
const PREF_SYSTEM_TOPSTORIES = "feeds.system.topstories";
const PREF_SHOW_SPONSORED = "showSponsored";
const PREF_SYSTEM_SHOW_SPONSORED = "system.showSponsored";
/**
* - Writes clicks and impressions to NewTabAttributionService.
* - Cleared when user history is cleared.
*/
export class NewTabAttributionFeed {
constructor() {
this.loaded = false;
}
isEnabled() {
const { values } = this.store.getState().Prefs;
const systemPref = values[PREF_SYSTEM_ATTRIBUTION];
const experimentVariable = values.trainhopConfig?.attribution?.enabled;
// Check all shortcuts prefs
const tilesEnabled =
values[PREF_FEED_TOPSITES] && values[PREF_SYSTEM_TOPSITES];
// Check all sponsored shortcuts prefs
const sponsoredTilesEnabled =
values[PREF_SHOW_SPONSORED_TOPSITES] &&
values[PREF_UNIFIED_ADS_TILES_ENABLED];
// Check all stories prefs
const storiesEnabled =
values[PREF_FEED_SECTION_TOPSTORIES] && values[PREF_SYSTEM_TOPSTORIES];
// Check all sponsored stories prefs
const sponsoredStoriesEnabled =
values[PREF_UNIFIED_ADS_SPOCS_ENABLED] &&
values[PREF_SYSTEM_SHOW_SPONSORED] &&
values[PREF_SHOW_SPONSORED];
// Confirm at least one ads section (tiles, spocs) are enabled to allow attribution
return (
(systemPref || experimentVariable) &&
((tilesEnabled && sponsoredTilesEnabled) ||
(storiesEnabled && sponsoredStoriesEnabled))
);
}
async init() {
this.attributionService = new lazy.NewTabAttributionService();
this.loaded = true;
}
uninit() {
this.attributionService = null;
this.loaded = false;
}
async onPlacesHistoryCleared() {
await this.attributionService?.onAttributionReset();
}
async onPrefChangedAction(action) {
switch (action.data.name) {
case PREF_SYSTEM_ATTRIBUTION:
case "trainhopConfig":
case PREF_UNIFIED_ADS_SPOCS_ENABLED:
case PREF_UNIFIED_ADS_TILES_ENABLED:
case PREF_FEED_TOPSITES:
case PREF_SYSTEM_TOPSITES:
case PREF_SHOW_SPONSORED_TOPSITES:
case PREF_FEED_SECTION_TOPSTORIES:
case PREF_SYSTEM_TOPSTORIES:
case PREF_SHOW_SPONSORED:
case PREF_SYSTEM_SHOW_SPONSORED: {
const enabled = this.isEnabled();
if (enabled && !this.loaded) {
await this.init();
} else if (!enabled && this.loaded) {
await this.onPlacesHistoryCleared();
this.uninit();
}
break;
}
}
}
async onAction(action) {
switch (action.type) {
case at.INIT:
if (this.isEnabled() && !this.loaded) {
await this.init();
}
break;
case at.UNINIT:
this.uninit();
break;
case at.PLACES_HISTORY_CLEARED:
await this.onPlacesHistoryCleared();
break;
case at.TOP_SITES_SPONSORED_IMPRESSION_STATS:
if (this.loaded && this.isEnabled()) {
const item = action?.data || {};
if (item.attribution) {
if (item.type === "impression") {
await this.attributionService.onAttributionEvent(
"view",
item.attribution
);
} else if (item.type === "click") {
await this.attributionService.onAttributionEvent(
"click",
item.attribution
);
}
}
}
break;
case at.DISCOVERY_STREAM_IMPRESSION_STATS:
if (this.loaded && this.isEnabled()) {
const item = action?.data?.tiles?.[0] || {};
if (item.attribution) {
await this.attributionService.onAttributionEvent(
"view",
item.attribution
);
}
}
break;
case at.DISCOVERY_STREAM_USER_EVENT:
if (this.loaded && this.isEnabled()) {
const item = action?.data?.value || {};
if (item.attribution) {
await this.attributionService.onAttributionEvent(
"click",
item.attribution
);
}
}
break;
case at.PREF_CHANGED:
await this.onPrefChangedAction(action);
break;
}
}
}