Wed, 31 Dec 2014 06:55:46 +0100
Added tag TORBROWSER_REPLICA for changeset 6474c204b198
1 #ifdef 0
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 file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #endif
7 /**
8 * This singleton represents the whole 'New Tab Page' and takes care of
9 * initializing all its components.
10 */
11 let gPage = {
12 /**
13 * Initializes the page.
14 */
15 init: function Page_init() {
16 // Add ourselves to the list of pages to receive notifications.
17 gAllPages.register(this);
19 // Listen for 'unload' to unregister this page.
20 addEventListener("unload", this, false);
22 // XXX bug 991111 - Not all click events are correctly triggered when
23 // listening from xhtml nodes -- in particular middle clicks on sites, so
24 // listen from the xul window and filter then delegate
25 addEventListener("click", this, false);
27 // Initialize sponsored panel
28 this._sponsoredPanel = document.getElementById("sponsored-panel");
29 let link = this._sponsoredPanel.querySelector(".text-link");
30 link.addEventListener("click", () => this._sponsoredPanel.hidePopup());
31 if (UpdateChannel.get().startsWith("release")) {
32 document.getElementById("sponsored-panel-trial-descr").style.display = "none";
33 }
34 else {
35 document.getElementById("sponsored-panel-release-descr").style.display = "none";
36 }
38 // Check if the new tab feature is enabled.
39 let enabled = gAllPages.enabled;
40 if (enabled)
41 this._init();
43 this._updateAttributes(enabled);
44 },
46 /**
47 * True if the page is allowed to capture thumbnails using the background
48 * thumbnail service.
49 */
50 get allowBackgroundCaptures() {
51 // The preloader is bypassed altogether for private browsing windows, and
52 // therefore allow-background-captures will not be set. In that case, the
53 // page is not preloaded and so it's visible, so allow background captures.
54 return inPrivateBrowsingMode() ||
55 document.documentElement.getAttribute("allow-background-captures") ==
56 "true";
57 },
59 /**
60 * Listens for notifications specific to this page.
61 */
62 observe: function Page_observe(aSubject, aTopic, aData) {
63 if (aTopic == "nsPref:changed") {
64 let enabled = gAllPages.enabled;
65 this._updateAttributes(enabled);
67 // Initialize the whole page if we haven't done that, yet.
68 if (enabled) {
69 this._init();
70 } else {
71 gUndoDialog.hide();
72 }
73 } else if (aTopic == "page-thumbnail:create" && gGrid.ready) {
74 for (let site of gGrid.sites) {
75 if (site && site.url === aData) {
76 site.refreshThumbnail();
77 }
78 }
79 }
80 },
82 /**
83 * Updates the whole page and the grid when the storage has changed.
84 * @param aOnlyIfHidden If true, the page is updated only if it's hidden in
85 * the preloader.
86 */
87 update: function Page_update(aOnlyIfHidden=false) {
88 let skipUpdate = aOnlyIfHidden && this.allowBackgroundCaptures;
89 // The grid might not be ready yet as we initialize it asynchronously.
90 if (gGrid.ready && !skipUpdate) {
91 gGrid.refresh();
92 }
93 },
95 /**
96 * Shows sponsored panel
97 */
98 showSponsoredPanel: function Page_showSponsoredPanel(aTarget) {
99 if (this._sponsoredPanel.state == "closed") {
100 let self = this;
101 this._sponsoredPanel.addEventListener("popuphidden", function onPopupHidden(aEvent) {
102 self._sponsoredPanel.removeEventListener("popuphidden", onPopupHidden, false);
103 aTarget.removeAttribute("panelShown");
104 });
105 }
106 aTarget.setAttribute("panelShown", "true");
107 this._sponsoredPanel.openPopup(aTarget);
108 },
110 /**
111 * Internally initializes the page. This runs only when/if the feature
112 * is/gets enabled.
113 */
114 _init: function Page_init() {
115 if (this._initialized)
116 return;
118 this._initialized = true;
120 gSearch.init();
122 this._mutationObserver = new MutationObserver(() => {
123 if (this.allowBackgroundCaptures) {
124 Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true);
126 // Initialize type counting with the types we want to count
127 let directoryCount = {};
128 for (let type of DirectoryLinksProvider.linkTypes) {
129 directoryCount[type] = 0;
130 }
132 for (let site of gGrid.sites) {
133 if (site) {
134 site.captureIfMissing();
135 let {type} = site.link;
136 if (type in directoryCount) {
137 directoryCount[type]++;
138 }
139 }
140 }
142 // Record how many directory sites were shown, but place counts over the
143 // default 9 in the same bucket
144 for (let [type, count] of Iterator(directoryCount)) {
145 let shownId = "NEWTAB_PAGE_DIRECTORY_" + type.toUpperCase() + "_SHOWN";
146 let shownCount = Math.min(10, count);
147 Services.telemetry.getHistogramById(shownId).add(shownCount);
148 }
150 // content.js isn't loaded for the page while it's in the preloader,
151 // which is why this is necessary.
152 gSearch.setUpInitialState();
153 }
154 });
155 this._mutationObserver.observe(document.documentElement, {
156 attributes: true,
157 attributeFilter: ["allow-background-captures"],
158 });
160 gLinks.populateCache(function () {
161 // Initialize and render the grid.
162 gGrid.init();
164 // Initialize the drop target shim.
165 gDropTargetShim.init();
167 #ifdef XP_MACOSX
168 // Workaround to prevent a delay on MacOSX due to a slow drop animation.
169 document.addEventListener("dragover", this, false);
170 document.addEventListener("drop", this, false);
171 #endif
172 }.bind(this));
173 },
175 /**
176 * Updates the 'page-disabled' attributes of the respective DOM nodes.
177 * @param aValue Whether the New Tab Page is enabled or not.
178 */
179 _updateAttributes: function Page_updateAttributes(aValue) {
180 // Set the nodes' states.
181 let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid, #newtab-search-container";
182 for (let node of document.querySelectorAll(nodeSelector)) {
183 if (aValue)
184 node.removeAttribute("page-disabled");
185 else
186 node.setAttribute("page-disabled", "true");
187 }
189 // Enables/disables the control and link elements.
190 let inputSelector = ".newtab-control, .newtab-link";
191 for (let input of document.querySelectorAll(inputSelector)) {
192 if (aValue)
193 input.removeAttribute("tabindex");
194 else
195 input.setAttribute("tabindex", "-1");
196 }
198 // Update the toggle button's title.
199 let toggle = document.getElementById("newtab-toggle");
200 toggle.setAttribute("title", newTabString(aValue ? "hide" : "show"));
201 },
203 /**
204 * Handles all page events.
205 */
206 handleEvent: function Page_handleEvent(aEvent) {
207 switch (aEvent.type) {
208 case "unload":
209 if (this._mutationObserver)
210 this._mutationObserver.disconnect();
211 gAllPages.unregister(this);
212 break;
213 case "click":
214 let {button, target} = aEvent;
215 if (target.id == "newtab-toggle") {
216 if (button == 0) {
217 gAllPages.enabled = !gAllPages.enabled;
218 }
219 break;
220 }
222 // Go up ancestors until we find a Site or not
223 while (target) {
224 if (target.hasOwnProperty("_newtabSite")) {
225 target._newtabSite.onClick(aEvent);
226 break;
227 }
228 target = target.parentNode;
229 }
230 break;
231 case "dragover":
232 if (gDrag.isValid(aEvent) && gDrag.draggedSite)
233 aEvent.preventDefault();
234 break;
235 case "drop":
236 if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
237 aEvent.preventDefault();
238 aEvent.stopPropagation();
239 }
240 break;
241 }
242 }
243 };