Bug 1072364 - Introducing History.jsm r=mak sr=gavin
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Wed, 08 Oct 2014 15:01:13 +0200
changeset 234221 97b76ccf75dc9e9fe76b72ebad9f0790aeef0ae2
parent 234220 424b31d77d2af4d13b5fd04cf574ffe0f05be668
child 234222 3e9de16c4c17411649cb5aa617ee64d1f66d5e38
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak, gavin
bugs1072364
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1072364 - Introducing History.jsm r=mak sr=gavin
toolkit/components/places/History.jsm
toolkit/components/places/PlacesUtils.jsm
toolkit/components/places/moz.build
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/History.jsm
@@ -0,0 +1,259 @@
+/* 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/. */
+
+"use strict";
+
+/**
+ * Asynchronous API for managing history.
+ *
+ *
+ * The API makes use of `PageInfo` and `VisitInfo` objects, defined as follows.
+ *
+ * A `PageInfo` object is any object that contains A SUBSET of the
+ * following properties:
+ * - guid: (string)
+ *     The globally unique id of the page.
+ * - uri: (URL)
+ *     or (nsIURI)
+ *     or (string)
+ *     The full URI of the page. Note that `PageInfo` values passed as
+ *     argument may hold `nsIURI` or `string` values for property `uri`,
+ *     but `PageInfo` objects returned by this module always hold `URL`
+ *     values.
+ * - title: (string)
+ *     The title associated with the page, if any.
+ * - frecency: (number)
+ *     The frecency of the page, if any.
+ *     See https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Places/Frecency_algorithm
+ *     Note that this property may not be used to change the actualy frecency
+ *     score of a page, only to retrieve it. In other words, any `frecency` field
+ *     passed as argument to a function of this API will be ignored.
+ *  - visits: (Array<VisitInfo>)
+ *     All the visits for this page, if any.
+ *
+ * See the documentation of individual methods to find out which properties
+ * are required for `PageInfo` arguments or returned for `PageInfo` results.
+ *
+ * A `VisitInfo` object is any object that contains A SUBSET of the following
+ * properties:
+ * - date: (Date)
+ *     The time the visit occurred.
+ * - transition: (number)
+ *     How the user reached the page. See constants `TRANSITION_*`
+ *     for the possible transition types.
+ * - referrer: (URL)
+ *          or (nsIURI)
+ *          or (string)
+ *     The referring URI of this visit. Note that `VisitInfo` passed
+ *     as argument may hold `nsIURI` or `string` values for property `referrer`,
+ *     but `VisitInfo` objects returned by this module always hold `URL`
+ *     values.
+ * See the documentation of individual methods to find out which properties
+ * are required for `VisitInfo` arguments or returned for `VisitInfo` results.
+ *
+ *
+ *
+ * Each successful operation notifies through the nsINavHistoryObserver
+ * interface. To listen to such notifications you must register using
+ * nsINavHistoryService `addObserver` and `removeObserver` methods.
+ * @see nsINavHistoryObserver
+ */
+
+this.EXPORTED_SYMBOLS = [ "History" ];
+
+const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+                                  "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                  "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+                                  "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+                                  "resource://gre/modules/Task.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
+                                  "resource://gre/modules/Sqlite.jsm");
+
+
+this.History = Object.freeze({
+  /**
+   * Fetch the available information for one page.
+   *
+   * @param guidOrURI: (URL or nsIURI)
+   *      The full URI of the page.
+   *            or (string)
+   *      Either the full URI of the page or the GUID of the page.
+   *
+   * @return (Promise)
+   *      A promise resolved once the operation is complete.
+   * @resolves (PageInfo | null) If the page could be found, the information
+   *      on that page. Note that this `PageInfo` does NOT contain the visit
+   *      data (i.e. `visits` is `undefined`).
+   *
+   * @throws (Error)
+   *      If `guidOrURI` does not have the expected type or if it is a string
+   *      that may be parsed neither as a valid URL nor as a valid GUID.
+   */
+  fetch: function (guidOrURI) {
+    throw new Error("Method not implemented");
+  },
+
+  /**
+   * Adds a set of visits for one or more page.
+   *
+   * Any change may be observed through nsINavHistoryObserver
+   *
+   * @note This function recomputes the frecency of the page automatically,
+   * regardless of the value of property `frecency` passed as argument.
+   * @note If there is no entry for the page, the entry is created.
+   *
+   * @param infos: (PageInfo)
+   *      Information on a page. This `PageInfo` MUST contain
+   *        - either a property `guid` or a property `uri`, as specified
+   *          by the definition of `PageInfo`;
+   *        - a property `visits`, as specified by the definition of
+   *          `PageInfo`, which MUST contain at least one visit.
+   *      If a property `title` is provided, the title of the page
+   *      is updated.
+   *      If the `visitDate` of a visit is not provided, it defaults
+   *      to now.
+   *            or (Array<PageInfo>)
+   *      An array of the above, to batch requests.
+   * @param onResult: (function(PageInfo), [optional])
+   *      A callback invoked for each page, with the updated
+   *      information on that page. Note that this `PageInfo`
+   *      does NOT contain the visit data (i.e. `visits` is
+   *      `undefined`).
+   *
+   * @return (Promise)
+   *      A promise resolved once the operation is complete, including
+   *      all calls to `onResult`.
+   * @resolves (bool)
+   *      `true` if at least one page entry was created, `false` otherwise
+   *       (i.e. if page entries were updated but not created).
+   *
+   * @throws (Error)
+   *      If the `uri` specified was for a protocol that should not be
+   *      stored (e.g. "chrome:", "mailbox:", "about:", "imap:", "news:",
+   *      "moz-anno:", "view-source:", "resource:", "data:", "wyciwyg:",
+   *      "javascript:", "blob:").
+   * @throws (Error)
+   *      If `infos` has an unexpected type.
+   * @throws (Error)
+   *      If a `PageInfo` has neither `guid` nor `uri`,
+   * @throws (Error)
+   *      If a `guid` property provided is not a valid GUID.
+   * @throws (Error)
+   *      If a `PageInfo` does not have a `visits` property or if the
+   *      value of `visits` is ill-typed or is an empty array.
+   * @throws (Error)
+   *      If an element of `visits` has an invalid `date`.
+   * @throws (Error)
+   *      If an element of `visits` is missing `transition` or if
+   *      the value of `transition` is invalid.
+   */
+  update: function (infos, onResult) {
+    throw new Error("Method not implemented");
+  },
+
+  /**
+   * Remove pages from the database.
+   *
+   * Any change may be observed through nsINavHistoryObserver
+   *
+   *
+   * @param page: (URL or nsIURI)
+   *      The full URI of the page.
+   *             or (string)
+   *      Either the full URI of the page or the GUID of the page.
+   *             or (Array<URL|nsIURI|string>)
+   *      An array of the above, to batch requests.
+   * @param onResult: (function(PageInfo))
+   *      A callback invoked for each page found.
+   *
+   * @return (Promise)
+   *      A promise resoled once the operation is complete.
+   * @resolve (bool)
+   *      `true` if at least one page was removed, `false` otherwise.
+   * @throws (Error)
+   *       If `pages` has an unexpected type or if a string provided
+   *       is neither a valid GUID nor a valid URI.
+   */
+  remove: function (pages, onResult) {
+    throw new Error("Method not implemented");
+  },
+
+  /**
+   * Determine if a page has been visited.
+   *
+   * @param pages: (URL or nsIURI)
+   *      The full URI of the page.
+   *            or (string)
+   *      The full URI of the page or the GUID of the page.
+   *
+   * @return (Promise)
+   *      A promise resoled once the operation is complete.
+   * @resolve (bool)
+   *      `true` if the page has been visited, `false` otherwise.
+   * @throws (Error)
+   *      If `pages` has an unexpected type or if a string provided
+   *      is neither not a valid GUID nor a valid URI.
+   */
+  hasVisits: function(page, onResult) {
+    throw new Error("Method not implemented");
+  },
+
+  /**
+   * Possible values for the `transition` property of `VisitInfo`
+   * objects.
+   */
+
+  /**
+   * The user followed a link and got a new toplevel window.
+   */
+  TRANSITION_LINK: Ci.nsINavHistoryService.TRANSITION_LINK,
+
+  /**
+   * The user typed the page's URL in the URL bar or selected it from
+   * URL bar autocomplete results, clicked on it from a history query
+   * (from the History sidebar, History menu, or history query in the
+   * personal toolbar or Places organizer.
+   */
+  TRANSITION_TYPED: Ci.nsINavHistoryService.TRANSITION_TYPED,
+
+  /**
+   * The user followed a bookmark to get to the page.
+   */
+  TRANSITION_BOOKMARK: Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
+
+  /**
+   * Some inner content is loaded. This is true of all images on a
+   * page, and the contents of the iframe. It is also true of any
+   * content in a frame if the user did not explicitly follow a link
+   * to get there.
+   */
+  TRANSITION_EMBED: Ci.nsINavHistoryService.TRANSITION_EMBED,
+
+  /**
+   * Set when the transition was a permanent redirect.
+   */
+  TRANSITION_REDIRECT_PERMANENT: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
+
+  /**
+   * Set when the transition was a temporary redirect.
+   */
+  TRANSITION_REDIRECT_TEMPORARY: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
+
+  /**
+   * Set when the transition is a download.
+   */
+  TRANSITION_DOWNLOAD: Ci.nsINavHistoryService.TRANSITION_REDIRECT_DOWNLOAD,
+
+  /**
+   * The user followed a link and got a visit in a frame.
+   */
+  TRANSITION_FRAMED_LINK: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
+});
+
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -39,16 +39,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
                                   "resource://gre/modules/Deprecated.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Bookmarks",
                                   "resource://gre/modules/Bookmarks.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "History",
+                                  "resource://gre/modules/History.jsm");
 
 // The minimum amount of transactions before starting a batch. Usually we do
 // do incremental updates, a batch will cause views to completely
 // refresh instead.
 const MIN_TRANSACTIONS_FOR_BATCH = 5;
 
 #ifdef XP_MACOSX
 // On Mac OSX, the transferable system converts "\r\n" to "\n\n", where we
@@ -1826,20 +1828,36 @@ this.PlacesUtils = {
                       rootItemCreationEx);
     }
 
     return rootItem;
   })
 };
 
 XPCOMUtils.defineLazyGetter(PlacesUtils, "history", function() {
-  return Cc["@mozilla.org/browser/nav-history-service;1"]
-           .getService(Ci.nsINavHistoryService)
-           .QueryInterface(Ci.nsIBrowserHistory)
-           .QueryInterface(Ci.nsPIPlacesDatabase);
+  let hs = Cc["@mozilla.org/browser/nav-history-service;1"]
+             .getService(Ci.nsINavHistoryService)
+             .QueryInterface(Ci.nsIBrowserHistory)
+             .QueryInterface(Ci.nsPIPlacesDatabase);
+  return Object.freeze(new Proxy(hs, {
+    get: function(target, name) {
+      let property, object;
+      if (name in target) {
+        property = target[name];
+        object = target;
+      } else {
+        property = History[name];
+        object = History;
+      }
+      if (typeof property == "function") {
+        return property.bind(object);
+      }
+      return property;
+    }
+  }));
 });
 
 XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "asyncHistory",
                                    "@mozilla.org/browser/history;1",
                                    "mozIAsyncHistory");
 
 XPCOMUtils.defineLazyGetter(PlacesUtils, "bhistory", function() {
   return PlacesUtils.history;
--- a/toolkit/components/places/moz.build
+++ b/toolkit/components/places/moz.build
@@ -61,16 +61,17 @@ if CONFIG['MOZ_PLACES']:
 
     EXTRA_JS_MODULES += [
         'BookmarkHTMLUtils.jsm',
         'BookmarkJSONUtils.jsm',
         'Bookmarks.jsm',
         'ClusterLib.js',
         'ColorAnalyzer_worker.js',
         'ColorConversion.js',
+        'History.jsm',
         'PlacesBackups.jsm',
         'PlacesDBUtils.jsm',
         'PlacesSearchAutocompleteProvider.jsm',
         'PlacesTransactions.jsm',
     ]
 
     EXTRA_PP_JS_MODULES += [
         'PlacesUtils.jsm',