1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/newtab/page.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,243 @@ 1.4 +#ifdef 0 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#endif 1.9 + 1.10 +/** 1.11 + * This singleton represents the whole 'New Tab Page' and takes care of 1.12 + * initializing all its components. 1.13 + */ 1.14 +let gPage = { 1.15 + /** 1.16 + * Initializes the page. 1.17 + */ 1.18 + init: function Page_init() { 1.19 + // Add ourselves to the list of pages to receive notifications. 1.20 + gAllPages.register(this); 1.21 + 1.22 + // Listen for 'unload' to unregister this page. 1.23 + addEventListener("unload", this, false); 1.24 + 1.25 + // XXX bug 991111 - Not all click events are correctly triggered when 1.26 + // listening from xhtml nodes -- in particular middle clicks on sites, so 1.27 + // listen from the xul window and filter then delegate 1.28 + addEventListener("click", this, false); 1.29 + 1.30 + // Initialize sponsored panel 1.31 + this._sponsoredPanel = document.getElementById("sponsored-panel"); 1.32 + let link = this._sponsoredPanel.querySelector(".text-link"); 1.33 + link.addEventListener("click", () => this._sponsoredPanel.hidePopup()); 1.34 + if (UpdateChannel.get().startsWith("release")) { 1.35 + document.getElementById("sponsored-panel-trial-descr").style.display = "none"; 1.36 + } 1.37 + else { 1.38 + document.getElementById("sponsored-panel-release-descr").style.display = "none"; 1.39 + } 1.40 + 1.41 + // Check if the new tab feature is enabled. 1.42 + let enabled = gAllPages.enabled; 1.43 + if (enabled) 1.44 + this._init(); 1.45 + 1.46 + this._updateAttributes(enabled); 1.47 + }, 1.48 + 1.49 + /** 1.50 + * True if the page is allowed to capture thumbnails using the background 1.51 + * thumbnail service. 1.52 + */ 1.53 + get allowBackgroundCaptures() { 1.54 + // The preloader is bypassed altogether for private browsing windows, and 1.55 + // therefore allow-background-captures will not be set. In that case, the 1.56 + // page is not preloaded and so it's visible, so allow background captures. 1.57 + return inPrivateBrowsingMode() || 1.58 + document.documentElement.getAttribute("allow-background-captures") == 1.59 + "true"; 1.60 + }, 1.61 + 1.62 + /** 1.63 + * Listens for notifications specific to this page. 1.64 + */ 1.65 + observe: function Page_observe(aSubject, aTopic, aData) { 1.66 + if (aTopic == "nsPref:changed") { 1.67 + let enabled = gAllPages.enabled; 1.68 + this._updateAttributes(enabled); 1.69 + 1.70 + // Initialize the whole page if we haven't done that, yet. 1.71 + if (enabled) { 1.72 + this._init(); 1.73 + } else { 1.74 + gUndoDialog.hide(); 1.75 + } 1.76 + } else if (aTopic == "page-thumbnail:create" && gGrid.ready) { 1.77 + for (let site of gGrid.sites) { 1.78 + if (site && site.url === aData) { 1.79 + site.refreshThumbnail(); 1.80 + } 1.81 + } 1.82 + } 1.83 + }, 1.84 + 1.85 + /** 1.86 + * Updates the whole page and the grid when the storage has changed. 1.87 + * @param aOnlyIfHidden If true, the page is updated only if it's hidden in 1.88 + * the preloader. 1.89 + */ 1.90 + update: function Page_update(aOnlyIfHidden=false) { 1.91 + let skipUpdate = aOnlyIfHidden && this.allowBackgroundCaptures; 1.92 + // The grid might not be ready yet as we initialize it asynchronously. 1.93 + if (gGrid.ready && !skipUpdate) { 1.94 + gGrid.refresh(); 1.95 + } 1.96 + }, 1.97 + 1.98 + /** 1.99 + * Shows sponsored panel 1.100 + */ 1.101 + showSponsoredPanel: function Page_showSponsoredPanel(aTarget) { 1.102 + if (this._sponsoredPanel.state == "closed") { 1.103 + let self = this; 1.104 + this._sponsoredPanel.addEventListener("popuphidden", function onPopupHidden(aEvent) { 1.105 + self._sponsoredPanel.removeEventListener("popuphidden", onPopupHidden, false); 1.106 + aTarget.removeAttribute("panelShown"); 1.107 + }); 1.108 + } 1.109 + aTarget.setAttribute("panelShown", "true"); 1.110 + this._sponsoredPanel.openPopup(aTarget); 1.111 + }, 1.112 + 1.113 + /** 1.114 + * Internally initializes the page. This runs only when/if the feature 1.115 + * is/gets enabled. 1.116 + */ 1.117 + _init: function Page_init() { 1.118 + if (this._initialized) 1.119 + return; 1.120 + 1.121 + this._initialized = true; 1.122 + 1.123 + gSearch.init(); 1.124 + 1.125 + this._mutationObserver = new MutationObserver(() => { 1.126 + if (this.allowBackgroundCaptures) { 1.127 + Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true); 1.128 + 1.129 + // Initialize type counting with the types we want to count 1.130 + let directoryCount = {}; 1.131 + for (let type of DirectoryLinksProvider.linkTypes) { 1.132 + directoryCount[type] = 0; 1.133 + } 1.134 + 1.135 + for (let site of gGrid.sites) { 1.136 + if (site) { 1.137 + site.captureIfMissing(); 1.138 + let {type} = site.link; 1.139 + if (type in directoryCount) { 1.140 + directoryCount[type]++; 1.141 + } 1.142 + } 1.143 + } 1.144 + 1.145 + // Record how many directory sites were shown, but place counts over the 1.146 + // default 9 in the same bucket 1.147 + for (let [type, count] of Iterator(directoryCount)) { 1.148 + let shownId = "NEWTAB_PAGE_DIRECTORY_" + type.toUpperCase() + "_SHOWN"; 1.149 + let shownCount = Math.min(10, count); 1.150 + Services.telemetry.getHistogramById(shownId).add(shownCount); 1.151 + } 1.152 + 1.153 + // content.js isn't loaded for the page while it's in the preloader, 1.154 + // which is why this is necessary. 1.155 + gSearch.setUpInitialState(); 1.156 + } 1.157 + }); 1.158 + this._mutationObserver.observe(document.documentElement, { 1.159 + attributes: true, 1.160 + attributeFilter: ["allow-background-captures"], 1.161 + }); 1.162 + 1.163 + gLinks.populateCache(function () { 1.164 + // Initialize and render the grid. 1.165 + gGrid.init(); 1.166 + 1.167 + // Initialize the drop target shim. 1.168 + gDropTargetShim.init(); 1.169 + 1.170 +#ifdef XP_MACOSX 1.171 + // Workaround to prevent a delay on MacOSX due to a slow drop animation. 1.172 + document.addEventListener("dragover", this, false); 1.173 + document.addEventListener("drop", this, false); 1.174 +#endif 1.175 + }.bind(this)); 1.176 + }, 1.177 + 1.178 + /** 1.179 + * Updates the 'page-disabled' attributes of the respective DOM nodes. 1.180 + * @param aValue Whether the New Tab Page is enabled or not. 1.181 + */ 1.182 + _updateAttributes: function Page_updateAttributes(aValue) { 1.183 + // Set the nodes' states. 1.184 + let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid, #newtab-search-container"; 1.185 + for (let node of document.querySelectorAll(nodeSelector)) { 1.186 + if (aValue) 1.187 + node.removeAttribute("page-disabled"); 1.188 + else 1.189 + node.setAttribute("page-disabled", "true"); 1.190 + } 1.191 + 1.192 + // Enables/disables the control and link elements. 1.193 + let inputSelector = ".newtab-control, .newtab-link"; 1.194 + for (let input of document.querySelectorAll(inputSelector)) { 1.195 + if (aValue) 1.196 + input.removeAttribute("tabindex"); 1.197 + else 1.198 + input.setAttribute("tabindex", "-1"); 1.199 + } 1.200 + 1.201 + // Update the toggle button's title. 1.202 + let toggle = document.getElementById("newtab-toggle"); 1.203 + toggle.setAttribute("title", newTabString(aValue ? "hide" : "show")); 1.204 + }, 1.205 + 1.206 + /** 1.207 + * Handles all page events. 1.208 + */ 1.209 + handleEvent: function Page_handleEvent(aEvent) { 1.210 + switch (aEvent.type) { 1.211 + case "unload": 1.212 + if (this._mutationObserver) 1.213 + this._mutationObserver.disconnect(); 1.214 + gAllPages.unregister(this); 1.215 + break; 1.216 + case "click": 1.217 + let {button, target} = aEvent; 1.218 + if (target.id == "newtab-toggle") { 1.219 + if (button == 0) { 1.220 + gAllPages.enabled = !gAllPages.enabled; 1.221 + } 1.222 + break; 1.223 + } 1.224 + 1.225 + // Go up ancestors until we find a Site or not 1.226 + while (target) { 1.227 + if (target.hasOwnProperty("_newtabSite")) { 1.228 + target._newtabSite.onClick(aEvent); 1.229 + break; 1.230 + } 1.231 + target = target.parentNode; 1.232 + } 1.233 + break; 1.234 + case "dragover": 1.235 + if (gDrag.isValid(aEvent) && gDrag.draggedSite) 1.236 + aEvent.preventDefault(); 1.237 + break; 1.238 + case "drop": 1.239 + if (gDrag.isValid(aEvent) && gDrag.draggedSite) { 1.240 + aEvent.preventDefault(); 1.241 + aEvent.stopPropagation(); 1.242 + } 1.243 + break; 1.244 + } 1.245 + } 1.246 +};