ChromeUtils.defineModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); ChromeUtils.defineModuleGetter(this, "Promise", "resource://gre/modules/commonjs/sdk/core/promise.js"); // Need to explicitly load profile for Places do_get_profile(); /** * Waits until a new cache entry has been opened * * @return {Promise} * @resolves When the new cache entry has been opened. * @rejects Never. * */ function promiseOpenCacheEntry(aKey, aAccessMode, aCacheSession) { let deferred = Promise.defer(); let cacheListener = { onCacheEntryAvailable: function (entry, access, status) { deferred.resolve(entry); }, onCacheEntryDoomed: function (status) { } }; aCacheSession.asyncOpenCacheEntry(aKey, aAccessMode, cacheListener); return deferred.promise; } /** * Waits for all pending async statements on the default connection. * * @return {Promise} * @resolves When all pending async statements finished. * @rejects Never. * * @note The result is achieved by asynchronously executing a query requiring * a write lock. Since all statements on the same connection are * serialized, the end of this write operation means that all writes are * complete. Note that WAL makes so that writers don't block readers, but * this is a problem only across different connections. */ function promiseAsyncUpdates() { let deferred = Promise.defer(); let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) .DBConnection; let begin = db.createAsyncStatement("BEGIN EXCLUSIVE"); begin.executeAsync(); begin.finalize(); let commit = db.createAsyncStatement("COMMIT"); commit.executeAsync({ handleResult: function() {}, handleError: function() {}, handleCompletion: function(aReason) { deferred.resolve(); } }); commit.finalize(); return deferred.promise; } /** * Asynchronously adds visits to a page. * * @param aPlaceInfo * Can be an nsIURI, in such a case a single LINK visit will be added. * Otherwise can be an object describing the visit to add, or an array * of these objects: * { uri: nsIURI of the page, * transition: one of the TRANSITION_* from nsINavHistoryService, * [optional] title: title of the page, * [optional] visitDate: visit date in microseconds from the epoch * [optional] referrer: nsIURI of the referrer for this visit * } * * @return {Promise} * @resolves When all visits have been added successfully. * @rejects JavaScript exception. */ function promiseAddVisits(aPlaceInfo) { let deferred = Promise.defer(); let places = []; if (aPlaceInfo instanceof Ci.nsIURI) { places.push({ uri: aPlaceInfo }); } else if (Array.isArray(aPlaceInfo)) { places = places.concat(aPlaceInfo); } else { places.push(aPlaceInfo) } // Create mozIVisitInfo for each entry. let now = Date.now(); for (let i = 0; i < places.length; i++) { if (!places[i].title) { places[i].title = "test visit for " + places[i].uri.spec; } places[i].visits = [{ transitionType: places[i].transition === undefined ? PlacesUtils.history.TRANSITION_LINK : places[i].transition, visitDate: places[i].visitDate || (now++) * 1000, referrerURI: places[i].referrer }]; } PlacesUtils.asyncHistory.updatePlaces( places, { handleError: function AAV_handleError(aResultCode, aPlaceInfo) { let ex = new Components.Exception("Unexpected error in adding visits.", aResultCode); deferred.reject(ex); }, handleResult: function () {}, handleCompletion: function UP_handleCompletion() { deferred.resolve(); } } ); return deferred.promise; }