toolkit/mozapps/downloads/DownloadLastDir.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/mozapps/downloads/DownloadLastDir.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,197 @@
     1.4 +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     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
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + * The behavior implemented by gDownloadLastDir is documented here.
    1.11 + *
    1.12 + * In normal browsing sessions, gDownloadLastDir uses the browser.download.lastDir
    1.13 + * preference to store the last used download directory. The first time the user
    1.14 + * switches into the private browsing mode, the last download directory is
    1.15 + * preserved to the pref value, but if the user switches to another directory
    1.16 + * during the private browsing mode, that directory is not stored in the pref,
    1.17 + * and will be merely kept in memory.  When leaving the private browsing mode,
    1.18 + * this in-memory value will be discarded, and the last download directory
    1.19 + * will be reverted to the pref value.
    1.20 + *
    1.21 + * Both the pref and the in-memory value will be cleared when clearing the
    1.22 + * browsing history.  This effectively changes the last download directory
    1.23 + * to the default download directory on each platform.
    1.24 + *
    1.25 + * If passed a URI, the last used directory is also stored with that URI in the
    1.26 + * content preferences database. This can be disabled by setting the pref
    1.27 + * browser.download.lastDir.savePerSite to false.
    1.28 + */
    1.29 +
    1.30 +const LAST_DIR_PREF = "browser.download.lastDir";
    1.31 +const SAVE_PER_SITE_PREF = LAST_DIR_PREF + ".savePerSite";
    1.32 +const nsIFile = Components.interfaces.nsIFile;
    1.33 +
    1.34 +this.EXPORTED_SYMBOLS = [ "DownloadLastDir" ];
    1.35 +
    1.36 +Components.utils.import("resource://gre/modules/Services.jsm");
    1.37 +Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
    1.38 +
    1.39 +let observer = {
    1.40 +  QueryInterface: function (aIID) {
    1.41 +    if (aIID.equals(Components.interfaces.nsIObserver) ||
    1.42 +        aIID.equals(Components.interfaces.nsISupports) ||
    1.43 +        aIID.equals(Components.interfaces.nsISupportsWeakReference))
    1.44 +      return this;
    1.45 +    throw Components.results.NS_NOINTERFACE;
    1.46 +  },
    1.47 +  observe: function (aSubject, aTopic, aData) {
    1.48 +    switch (aTopic) {
    1.49 +      case "last-pb-context-exited":
    1.50 +        gDownloadLastDirFile = null;
    1.51 +        break;
    1.52 +      case "browser:purge-session-history":
    1.53 +        gDownloadLastDirFile = null;
    1.54 +        if (Services.prefs.prefHasUserValue(LAST_DIR_PREF))
    1.55 +          Services.prefs.clearUserPref(LAST_DIR_PREF);
    1.56 +        // Ensure that purging session history causes both the session-only PB cache
    1.57 +        // and persistent prefs to be cleared.
    1.58 +        let cps2 = Components.classes["@mozilla.org/content-pref/service;1"].
    1.59 +                     getService(Components.interfaces.nsIContentPrefService2);
    1.60 +
    1.61 +        cps2.removeByName(LAST_DIR_PREF, {usePrivateBrowsing: false});
    1.62 +        cps2.removeByName(LAST_DIR_PREF, {usePrivateBrowsing: true});
    1.63 +        break;
    1.64 +    }
    1.65 +  }
    1.66 +};
    1.67 +
    1.68 +let os = Components.classes["@mozilla.org/observer-service;1"]
    1.69 +                   .getService(Components.interfaces.nsIObserverService);
    1.70 +os.addObserver(observer, "last-pb-context-exited", true);
    1.71 +os.addObserver(observer, "browser:purge-session-history", true);
    1.72 +
    1.73 +function readLastDirPref() {
    1.74 +  try {
    1.75 +    return Services.prefs.getComplexValue(LAST_DIR_PREF, nsIFile);
    1.76 +  }
    1.77 +  catch (e) {
    1.78 +    return null;
    1.79 +  }
    1.80 +}
    1.81 +
    1.82 +function isContentPrefEnabled() {
    1.83 +  try {
    1.84 +    return Services.prefs.getBoolPref(SAVE_PER_SITE_PREF);
    1.85 +  }
    1.86 +  catch (e) {
    1.87 +    return true;
    1.88 +  }
    1.89 +}
    1.90 +
    1.91 +let gDownloadLastDirFile = readLastDirPref();
    1.92 +
    1.93 +this.DownloadLastDir = function DownloadLastDir(aWindow) {
    1.94 +  this.window = aWindow;
    1.95 +}
    1.96 +
    1.97 +DownloadLastDir.prototype = {
    1.98 +  isPrivate: function DownloadLastDir_isPrivate() {
    1.99 +    return PrivateBrowsingUtils.isWindowPrivate(this.window);
   1.100 +  },
   1.101 +  // compat shims
   1.102 +  get file() this._getLastFile(),
   1.103 +  set file(val) { this.setFile(null, val); },
   1.104 +  cleanupPrivateFile: function () {
   1.105 +    gDownloadLastDirFile = null;
   1.106 +  },
   1.107 +  // This function is now deprecated as it uses the sync nsIContentPrefService
   1.108 +  // interface. New consumers should use the getFileAsync function.
   1.109 +  getFile: function (aURI) {
   1.110 +    let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated;
   1.111 +    Deprecated.warning("DownloadLastDir.getFile is deprecated. Please use getFileAsync instead.",
   1.112 +                       "https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/DownloadLastDir.jsm",
   1.113 +                       Components.stack.caller);
   1.114 +
   1.115 +    if (aURI && isContentPrefEnabled()) {
   1.116 +      let loadContext = this.window
   1.117 +                            .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   1.118 +                            .getInterface(Components.interfaces.nsIWebNavigation)
   1.119 +                            .QueryInterface(Components.interfaces.nsILoadContext);
   1.120 +      let lastDir = Services.contentPrefs.getPref(aURI, LAST_DIR_PREF, loadContext);
   1.121 +      if (lastDir) {
   1.122 +        var lastDirFile = Components.classes["@mozilla.org/file/local;1"]
   1.123 +                                    .createInstance(Components.interfaces.nsIFile);
   1.124 +        lastDirFile.initWithPath(lastDir);
   1.125 +        return lastDirFile;
   1.126 +      }
   1.127 +    }
   1.128 +    return this._getLastFile();
   1.129 +  },
   1.130 +
   1.131 +  _getLastFile: function () {
   1.132 +    if (gDownloadLastDirFile && !gDownloadLastDirFile.exists())
   1.133 +      gDownloadLastDirFile = null;
   1.134 +
   1.135 +    if (this.isPrivate()) {
   1.136 +      if (!gDownloadLastDirFile)
   1.137 +        gDownloadLastDirFile = readLastDirPref();
   1.138 +      return gDownloadLastDirFile;
   1.139 +    }
   1.140 +    return readLastDirPref();
   1.141 +  },
   1.142 +
   1.143 +  getFileAsync: function(aURI, aCallback) {
   1.144 +    let plainPrefFile = this._getLastFile();
   1.145 +    if (!aURI || !isContentPrefEnabled()) {
   1.146 +      Services.tm.mainThread.dispatch(function() aCallback(plainPrefFile),
   1.147 +                                      Components.interfaces.nsIThread.DISPATCH_NORMAL);
   1.148 +      return;
   1.149 +    }
   1.150 +
   1.151 +    let uri = aURI instanceof Components.interfaces.nsIURI ? aURI.spec : aURI;
   1.152 +    let cps2 = Components.classes["@mozilla.org/content-pref/service;1"]
   1.153 +                         .getService(Components.interfaces.nsIContentPrefService2);
   1.154 +    let loadContext = this.window
   1.155 +                          .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   1.156 +                          .getInterface(Components.interfaces.nsIWebNavigation)
   1.157 +                          .QueryInterface(Components.interfaces.nsILoadContext);
   1.158 +    let result = null;
   1.159 +    cps2.getByDomainAndName(uri, LAST_DIR_PREF, loadContext, {
   1.160 +      handleResult: function(aResult) result = aResult,
   1.161 +      handleCompletion: function(aReason) {
   1.162 +        let file = plainPrefFile;
   1.163 +        if (aReason == Components.interfaces.nsIContentPrefCallback2.COMPLETE_OK &&
   1.164 +           result instanceof Components.interfaces.nsIContentPref) {
   1.165 +          file = Components.classes["@mozilla.org/file/local;1"]
   1.166 +                           .createInstance(Components.interfaces.nsIFile);
   1.167 +          file.initWithPath(result.value);
   1.168 +        }
   1.169 +        aCallback(file);
   1.170 +      }
   1.171 +    });
   1.172 +  },
   1.173 +
   1.174 +  setFile: function (aURI, aFile) {
   1.175 +    if (aURI && isContentPrefEnabled()) {
   1.176 +      let uri = aURI instanceof Components.interfaces.nsIURI ? aURI.spec : aURI;
   1.177 +      let cps2 = Components.classes["@mozilla.org/content-pref/service;1"]
   1.178 +                           .getService(Components.interfaces.nsIContentPrefService2);
   1.179 +      let loadContext = this.window
   1.180 +                            .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   1.181 +                            .getInterface(Components.interfaces.nsIWebNavigation)
   1.182 +                            .QueryInterface(Components.interfaces.nsILoadContext);
   1.183 +      if (aFile instanceof Components.interfaces.nsIFile)
   1.184 +        cps2.set(uri, LAST_DIR_PREF, aFile.path, loadContext);
   1.185 +      else
   1.186 +        cps2.removeByDomainAndName(uri, LAST_DIR_PREF, loadContext);
   1.187 +    }
   1.188 +    if (this.isPrivate()) {
   1.189 +      if (aFile instanceof Components.interfaces.nsIFile)
   1.190 +        gDownloadLastDirFile = aFile.clone();
   1.191 +      else
   1.192 +        gDownloadLastDirFile = null;
   1.193 +    } else {
   1.194 +      if (aFile instanceof Components.interfaces.nsIFile)
   1.195 +        Services.prefs.setComplexValue(LAST_DIR_PREF, nsIFile, aFile);
   1.196 +      else if (Services.prefs.prefHasUserValue(LAST_DIR_PREF))
   1.197 +        Services.prefs.clearUserPref(LAST_DIR_PREF);
   1.198 +    }
   1.199 +  }
   1.200 +};

mercurial