forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			209 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* 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 kEnabledPref = "browser.laterrun.enabled";
 | |
| const kPagePrefRoot = "browser.laterrun.pages.";
 | |
| // Number of sessions we've been active in
 | |
| const kSessionCountPref = "browser.laterrun.bookkeeping.sessionCount";
 | |
| // Time the profile was created at in seconds:
 | |
| const kProfileCreationTime = "browser.laterrun.bookkeeping.profileCreationTime";
 | |
| // Time the update was applied at in seconds:
 | |
| const kUpdateAppliedTime = "browser.laterrun.bookkeeping.updateAppliedTime";
 | |
| 
 | |
| // After 50 sessions or 1 month since install, assume we will no longer be
 | |
| // interested in showing anything to "new" users
 | |
| const kSelfDestructSessionLimit = 50;
 | |
| const kSelfDestructHoursLimit = 31 * 24;
 | |
| 
 | |
| class Page {
 | |
|   constructor({
 | |
|     pref,
 | |
|     minimumHoursSinceInstall,
 | |
|     minimumSessionCount,
 | |
|     requireBoth,
 | |
|     url,
 | |
|   }) {
 | |
|     this.pref = pref;
 | |
|     this.minimumHoursSinceInstall = minimumHoursSinceInstall || 0;
 | |
|     this.minimumSessionCount = minimumSessionCount || 1;
 | |
|     this.requireBoth = requireBoth || false;
 | |
|     this.url = url;
 | |
|   }
 | |
| 
 | |
|   get hasRun() {
 | |
|     return Services.prefs.getBoolPref(this.pref + "hasRun", false);
 | |
|   }
 | |
| 
 | |
|   applies(sessionInfo) {
 | |
|     if (this.hasRun) {
 | |
|       return false;
 | |
|     }
 | |
|     if (this.requireBoth) {
 | |
|       return (
 | |
|         sessionInfo.sessionCount >= this.minimumSessionCount &&
 | |
|         sessionInfo.hoursSinceInstall >= this.minimumHoursSinceInstall
 | |
|       );
 | |
|     }
 | |
|     return (
 | |
|       sessionInfo.sessionCount >= this.minimumSessionCount ||
 | |
|       sessionInfo.hoursSinceInstall >= this.minimumHoursSinceInstall
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| export let LaterRun = {
 | |
|   get ENABLE_REASON_NEW_PROFILE() {
 | |
|     return 1;
 | |
|   },
 | |
|   get ENABLE_REASON_UPDATE_APPLIED() {
 | |
|     return 2;
 | |
|   },
 | |
| 
 | |
|   init(reason) {
 | |
|     if (!this.enabled) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (reason == this.ENABLE_REASON_NEW_PROFILE) {
 | |
|       // If this is the first run, set the time we were installed
 | |
|       if (
 | |
|         Services.prefs.getPrefType(kProfileCreationTime) ==
 | |
|         Ci.nsIPrefBranch.PREF_INVALID
 | |
|       ) {
 | |
|         // We need to store seconds in order to fit within int prefs.
 | |
|         Services.prefs.setIntPref(
 | |
|           kProfileCreationTime,
 | |
|           Math.floor(Date.now() / 1000)
 | |
|         );
 | |
|       }
 | |
|       this.sessionCount++;
 | |
|     } else if (reason == this.ENABLE_REASON_UPDATE_APPLIED) {
 | |
|       Services.prefs.setIntPref(
 | |
|         kUpdateAppliedTime,
 | |
|         Math.floor(Services.startup.getStartupInfo().start.getTime() / 1000)
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     if (
 | |
|       this.hoursSinceInstall > kSelfDestructHoursLimit ||
 | |
|       this.sessionCount > kSelfDestructSessionLimit
 | |
|     ) {
 | |
|       this.selfDestruct();
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   // The enabled, hoursSinceInstall and sessionCount properties mirror the
 | |
|   // preferences system, and are here for convenience.
 | |
|   get enabled() {
 | |
|     return Services.prefs.getBoolPref(kEnabledPref, false);
 | |
|   },
 | |
| 
 | |
|   enable(reason) {
 | |
|     if (!this.enabled) {
 | |
|       Services.prefs.setBoolPref(kEnabledPref, true);
 | |
|       this.init(reason);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   get hoursSinceInstall() {
 | |
|     let installStampSec = Services.prefs.getIntPref(
 | |
|       kProfileCreationTime,
 | |
|       Date.now() / 1000
 | |
|     );
 | |
|     return Math.floor((Date.now() / 1000 - installStampSec) / 3600);
 | |
|   },
 | |
| 
 | |
|   get hoursSinceUpdate() {
 | |
|     let updateStampSec = Services.prefs.getIntPref(kUpdateAppliedTime, 0);
 | |
|     return Math.floor((Date.now() / 1000 - updateStampSec) / 3600);
 | |
|   },
 | |
| 
 | |
|   get sessionCount() {
 | |
|     if (this._sessionCount) {
 | |
|       return this._sessionCount;
 | |
|     }
 | |
|     return (this._sessionCount = Services.prefs.getIntPref(
 | |
|       kSessionCountPref,
 | |
|       0
 | |
|     ));
 | |
|   },
 | |
| 
 | |
|   set sessionCount(val) {
 | |
|     this._sessionCount = val;
 | |
|     Services.prefs.setIntPref(kSessionCountPref, val);
 | |
|   },
 | |
| 
 | |
|   // Because we don't want to keep incrementing this indefinitely for no reason,
 | |
|   // we will turn ourselves off after a set amount of time/sessions (see top of
 | |
|   // file).
 | |
|   selfDestruct() {
 | |
|     Services.prefs.setBoolPref(kEnabledPref, false);
 | |
|   },
 | |
| 
 | |
|   // Create an array of Page objects based on the currently set prefs
 | |
|   readPages() {
 | |
|     // Enumerate all the pages.
 | |
|     let allPrefsForPages = Services.prefs.getChildList(kPagePrefRoot);
 | |
|     let pageDataStore = new Map();
 | |
|     for (let pref of allPrefsForPages) {
 | |
|       let [slug, prop] = pref.substring(kPagePrefRoot.length).split(".");
 | |
|       if (!pageDataStore.has(slug)) {
 | |
|         pageDataStore.set(slug, {
 | |
|           pref: pref.substring(0, pref.length - prop.length),
 | |
|         });
 | |
|       }
 | |
|       if (prop == "requireBoth" || prop == "hasRun") {
 | |
|         pageDataStore.get(slug)[prop] = Services.prefs.getBoolPref(pref, false);
 | |
|       } else if (prop == "url") {
 | |
|         pageDataStore.get(slug)[prop] = Services.prefs.getStringPref(pref, "");
 | |
|       } else {
 | |
|         pageDataStore.get(slug)[prop] = Services.prefs.getIntPref(pref, 0);
 | |
|       }
 | |
|     }
 | |
|     let rv = [];
 | |
|     for (let [, pageData] of pageDataStore) {
 | |
|       if (pageData.url) {
 | |
|         let uri = null;
 | |
|         try {
 | |
|           let urlString = Services.urlFormatter.formatURL(pageData.url.trim());
 | |
|           uri = Services.io.newURI(urlString);
 | |
|         } catch (ex) {
 | |
|           console.error(
 | |
|             "Invalid LaterRun page URL ",
 | |
|             pageData.url,
 | |
|             " ignored."
 | |
|           );
 | |
|           continue;
 | |
|         }
 | |
|         if (!uri.schemeIs("https")) {
 | |
|           console.error("Insecure LaterRun page URL ", uri.spec, " ignored.");
 | |
|         } else {
 | |
|           pageData.url = uri.spec;
 | |
|           rv.push(new Page(pageData));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return rv;
 | |
|   },
 | |
| 
 | |
|   // Return a URL for display as a 'later run' page if its criteria are matched,
 | |
|   // or null otherwise.
 | |
|   // NB: will only return one page at a time; if multiple pages match, it's up
 | |
|   // to the preference service which one gets shown first, and the next one
 | |
|   // will be shown next startup instead.
 | |
|   getURL() {
 | |
|     if (!this.enabled) {
 | |
|       return null;
 | |
|     }
 | |
|     let pages = this.readPages();
 | |
|     let page = pages.find(p => p.applies(this));
 | |
|     if (page) {
 | |
|       Services.prefs.setBoolPref(page.pref + "hasRun", true);
 | |
|       return page.url;
 | |
|     }
 | |
|     return null;
 | |
|   },
 | |
| };
 | |
| 
 | |
| LaterRun.init();
 | 
