This repository has been archived by the owner on Feb 29, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 113
/
TopSitesFeed.jsm
146 lines (134 loc) · 5.11 KB
/
TopSitesFeed.jsm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* 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/. */
"use strict";
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
const {insertPinned} = Cu.import("resource://activity-stream/common/Reducers.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Screenshots",
"resource://activity-stream/lib/Screenshots.jsm");
const TOP_SITES_SHOWMORE_LENGTH = 12;
const UPDATE_TIME = 15 * 60 * 1000; // 15 minutes
const DEFAULT_TOP_SITES = [];
this.TopSitesFeed = class TopSitesFeed {
constructor() {
this.lastUpdated = 0;
}
init() {
// Add default sites if any based on the pref
let sites = new Prefs().get("default.sites");
if (sites) {
for (const url of sites.split(",")) {
DEFAULT_TOP_SITES.push({
isDefault: true,
url
});
}
}
}
async getScreenshot(url) {
let screenshot = await Screenshots.getScreenshotForURL(url);
const action = {type: at.SCREENSHOT_UPDATED, data: {url, screenshot}};
this.store.dispatch(ac.BroadcastToContent(action));
}
async getLinksWithDefaults(action) {
let frecent = await NewTabUtils.activityStreamLinks.getTopSites();
const defaultUrls = DEFAULT_TOP_SITES.map(site => site.url);
let pinned = NewTabUtils.pinnedLinks.links;
pinned = pinned.map(site => site && Object.assign({}, site, {isDefault: defaultUrls.indexOf(site.url) !== -1}));
if (!frecent) {
frecent = [];
} else {
frecent = frecent.filter(link => link && link.type !== "affiliate");
}
return insertPinned([...frecent, ...DEFAULT_TOP_SITES], pinned).slice(0, TOP_SITES_SHOWMORE_LENGTH);
}
async refresh(target = null) {
const links = await this.getLinksWithDefaults();
// First, cache existing screenshots in case we need to reuse them
const currentScreenshots = {};
for (const link of this.store.getState().TopSites.rows) {
if (link && link.screenshot) {
currentScreenshots[link.url] = link.screenshot;
}
}
// Now, get a screenshot for every item
for (let link of links) {
if (!link) { continue; }
if (currentScreenshots[link.url]) {
link.screenshot = currentScreenshots[link.url];
} else {
this.getScreenshot(link.url);
}
}
const newAction = {type: at.TOP_SITES_UPDATED, data: links};
if (target) {
// Send an update to content so the preloaded tab can get the updated content
this.store.dispatch(ac.SendToContent(newAction, target));
} else {
// Broadcast an update to all open content pages
this.store.dispatch(ac.BroadcastToContent(newAction));
}
this.lastUpdated = Date.now();
}
_getPinnedWithData() {
// Augment the pinned links with any other extra data we have for them already in the store
const links = this.store.getState().TopSites.rows;
const pinned = NewTabUtils.pinnedLinks.links;
return pinned.map(pinnedLink => (pinnedLink ? Object.assign(links.find(link => link && link.url === pinnedLink.url) || {}, pinnedLink) : pinnedLink));
}
pin(action) {
const {site, index} = action.data;
NewTabUtils.pinnedLinks.pin(site, index);
this.store.dispatch(ac.BroadcastToContent({
type: at.PINNED_SITES_UPDATED,
data: this._getPinnedWithData()
}));
}
unpin(action) {
const {site} = action.data;
NewTabUtils.pinnedLinks.unpin(site);
this.store.dispatch(ac.BroadcastToContent({
type: at.PINNED_SITES_UPDATED,
data: this._getPinnedWithData()
}));
}
onAction(action) {
let realRows;
switch (action.type) {
case at.INIT:
this.init();
break;
case at.NEW_TAB_LOAD:
// Only check against real rows returned from history, not default ones.
realRows = this.store.getState().TopSites.rows.filter(row => !row.isDefault);
if (
// When a new tab is opened, if we don't have enough top sites yet, refresh the data.
(realRows.length < TOP_SITES_SHOWMORE_LENGTH) ||
// When a new tab is opened, if the last time we refreshed the data
// is greater than 15 minutes, refresh the data.
(Date.now() - this.lastUpdated >= UPDATE_TIME)
) {
this.refresh(action.meta.fromTarget);
}
break;
case at.PLACES_HISTORY_CLEARED:
this.refresh();
break;
case at.TOP_SITES_PIN:
this.pin(action);
break;
case at.TOP_SITES_UNPIN:
this.unpin(action);
break;
}
}
};
this.UPDATE_TIME = UPDATE_TIME;
this.TOP_SITES_SHOWMORE_LENGTH = TOP_SITES_SHOWMORE_LENGTH;
this.DEFAULT_TOP_SITES = DEFAULT_TOP_SITES;
this.EXPORTED_SYMBOLS = ["TopSitesFeed", "UPDATE_TIME", "DEFAULT_TOP_SITES", "TOP_SITES_SHOWMORE_LENGTH"];