Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
5 "use strict";
7 this.EXPORTED_SYMBOLS = ["DirectoryLinksProvider"];
9 const Ci = Components.interfaces;
10 const Cc = Components.classes;
11 const Cu = Components.utils;
13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
14 Cu.import("resource://gre/modules/Services.jsm");
16 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
17 "resource://gre/modules/NetUtil.jsm");
19 /**
20 * Gets the currently selected locale for display.
21 * @return the selected locale or "en-US" if none is selected
22 */
23 function getLocale() {
24 let matchOS;
25 try {
26 matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
27 }
28 catch (e) {}
30 if (matchOS) {
31 return Services.locale.getLocaleComponentForUserAgent();
32 }
34 try {
35 let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE,
36 Ci.nsIPrefLocalizedString);
37 if (locale) {
38 return locale.data;
39 }
40 }
41 catch (e) {}
43 try {
44 return Services.prefs.getCharPref(PREF_SELECTED_LOCALE);
45 }
46 catch (e) {}
48 return "en-US";
49 }
51 // The preference that tells whether to match the OS locale
52 const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
54 // The preference that tells what locale the user selected
55 const PREF_SELECTED_LOCALE = "general.useragent.locale";
57 // The preference that tells where to obtain directory links
58 const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directorySource";
60 // The frecency of a directory link
61 const DIRECTORY_FRECENCY = 1000;
63 const LINK_TYPES = Object.freeze([
64 "sponsored",
65 "affiliate",
66 "organic",
67 ]);
69 /**
70 * Singleton that serves as the provider of directory links.
71 * Directory links are a hard-coded set of links shown if a user's link
72 * inventory is empty.
73 */
74 let DirectoryLinksProvider = {
76 __linksURL: null,
78 _observers: [],
80 get _prefs() Object.freeze({
81 linksURL: PREF_DIRECTORY_SOURCE,
82 matchOSLocale: PREF_MATCH_OS_LOCALE,
83 prefSelectedLocale: PREF_SELECTED_LOCALE,
84 }),
86 get _linksURL() {
87 if (!this.__linksURL) {
88 try {
89 this.__linksURL = Services.prefs.getCharPref(this._prefs["linksURL"]);
90 }
91 catch (e) {
92 Cu.reportError("Error fetching directory links url from prefs: " + e);
93 }
94 }
95 return this.__linksURL;
96 },
98 get linkTypes() LINK_TYPES,
100 observe: function DirectoryLinksProvider_observe(aSubject, aTopic, aData) {
101 if (aTopic == "nsPref:changed") {
102 if (aData == this._prefs["linksURL"]) {
103 delete this.__linksURL;
104 }
105 this._callObservers("onManyLinksChanged");
106 }
107 },
109 _addPrefsObserver: function DirectoryLinksProvider_addObserver() {
110 for (let pref in this._prefs) {
111 let prefName = this._prefs[pref];
112 Services.prefs.addObserver(prefName, this, false);
113 }
114 },
116 _removePrefsObserver: function DirectoryLinksProvider_removeObserver() {
117 for (let pref in this._prefs) {
118 let prefName = this._prefs[pref];
119 Services.prefs.removeObserver(prefName, this);
120 }
121 },
123 /**
124 * Fetches the current set of directory links.
125 * @param aCallback a callback that is provided a set of links.
126 */
127 _fetchLinks: function DirectoryLinksProvider_fetchLinks(aCallback) {
128 try {
129 NetUtil.asyncFetch(this._linksURL, (aInputStream, aResult, aRequest) => {
130 let output;
131 if (Components.isSuccessCode(aResult)) {
132 try {
133 let json = NetUtil.readInputStreamToString(aInputStream,
134 aInputStream.available(),
135 {charset: "UTF-8"});
136 let locale = getLocale();
137 output = JSON.parse(json)[locale];
138 }
139 catch (e) {
140 Cu.reportError(e);
141 }
142 }
143 else {
144 Cu.reportError(new Error("the fetch of " + this._linksURL + "was unsuccessful"));
145 }
146 aCallback(output || []);
147 });
148 }
149 catch (e) {
150 Cu.reportError(e);
151 aCallback([]);
152 }
153 },
155 /**
156 * Gets the current set of directory links.
157 * @param aCallback The function that the array of links is passed to.
158 */
159 getLinks: function DirectoryLinksProvider_getLinks(aCallback) {
160 this._fetchLinks(rawLinks => {
161 // all directory links have a frecency of DIRECTORY_FRECENCY
162 aCallback(rawLinks.map((link, position) => {
163 link.frecency = DIRECTORY_FRECENCY;
164 link.lastVisitDate = rawLinks.length - position;
165 return link;
166 }));
167 });
168 },
170 init: function DirectoryLinksProvider_init() {
171 this._addPrefsObserver();
172 },
174 /**
175 * Return the object to its pre-init state
176 */
177 reset: function DirectoryLinksProvider_reset() {
178 delete this.__linksURL;
179 this._removePrefsObserver();
180 this._removeObservers();
181 },
183 addObserver: function DirectoryLinksProvider_addObserver(aObserver) {
184 this._observers.push(aObserver);
185 },
187 _callObservers: function DirectoryLinksProvider__callObservers(aMethodName, aArg) {
188 for (let obs of this._observers) {
189 if (typeof(obs[aMethodName]) == "function") {
190 try {
191 obs[aMethodName](this, aArg);
192 } catch (err) {
193 Cu.reportError(err);
194 }
195 }
196 }
197 },
199 _removeObservers: function() {
200 while (this._observers.length) {
201 this._observers.pop();
202 }
203 }
204 };