mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
8ee5ae1678
Differential Revision: https://phabricator.services.mozilla.com/D119310
254 lines
7.9 KiB
JavaScript
254 lines
7.9 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/. */
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* This module exports a provider, returning open tabs matches for the urlbar.
|
|
* It is also used to register and unregister open tabs.
|
|
*/
|
|
|
|
var EXPORTED_SYMBOLS = ["UrlbarProviderOpenTabs"];
|
|
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
);
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
|
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
|
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.jsm",
|
|
UrlbarResult: "resource:///modules/UrlbarResult.jsm",
|
|
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
|
});
|
|
|
|
const PRIVATE_USER_CONTEXT_ID = -1;
|
|
|
|
/**
|
|
* Class used to create the provider.
|
|
*/
|
|
class UrlbarProviderOpenTabs extends UrlbarProvider {
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
/**
|
|
* Returns the name of this provider.
|
|
* @returns {string} the name of this provider.
|
|
*/
|
|
get name() {
|
|
return "OpenTabs";
|
|
}
|
|
|
|
/**
|
|
* Returns the type of this provider.
|
|
* @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
|
|
*/
|
|
get type() {
|
|
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
|
|
}
|
|
|
|
/**
|
|
* Whether this provider should be invoked for the given context.
|
|
* If this method returns false, the providers manager won't start a query
|
|
* with this provider, to save on resources.
|
|
* @param {UrlbarQueryContext} queryContext The query context object
|
|
* @returns {boolean} Whether this provider should be invoked for the search.
|
|
*/
|
|
isActive(queryContext) {
|
|
// For now we don't actually use this provider to query open tabs, instead
|
|
// we join the temp table in UrlbarProviderPlaces.
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Tracks whether the memory tables have been initialized yet. Until this
|
|
* happens tabs are only stored in openTabs and later copied over to the
|
|
* memory table.
|
|
*/
|
|
static memoryTableInitialized = false;
|
|
|
|
/**
|
|
* Maps the open tabs by userContextId.
|
|
*/
|
|
static _openTabs = new Map();
|
|
|
|
/**
|
|
* Return urls that is opening on given user context id.
|
|
* @param {integer} userContextId Containers user context id
|
|
* @param {boolean} isInPrivateWindow In private browsing window or not
|
|
* @returns {Array} urls
|
|
*/
|
|
static getOpenTabs(userContextId, isInPrivateWindow) {
|
|
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
|
|
userContextId,
|
|
isInPrivateWindow
|
|
);
|
|
return UrlbarProviderOpenTabs._openTabs.get(userContextId);
|
|
}
|
|
|
|
/**
|
|
* Return userContextId that will be used in moz_openpages_temp table.
|
|
* @param {integer} userContextId Containers user context id
|
|
* @param {boolean} isInPrivateWindow In private browsing window or not
|
|
* @returns {interger} userContextId
|
|
*/
|
|
static getUserContextIdForOpenPagesTable(userContextId, isInPrivateWindow) {
|
|
return isInPrivateWindow ? PRIVATE_USER_CONTEXT_ID : userContextId;
|
|
}
|
|
|
|
/**
|
|
* Copy over cached open tabs to the memory table once the Urlbar
|
|
* connection has been initialized.
|
|
*/
|
|
static promiseDBPopulated = PlacesUtils.largeCacheDBConnDeferred.promise.then(
|
|
async () => {
|
|
// Must be set before populating.
|
|
UrlbarProviderOpenTabs.memoryTableInitialized = true;
|
|
// Populate the table with the current cached tabs.
|
|
for (let [userContextId, urls] of UrlbarProviderOpenTabs._openTabs) {
|
|
for (let url of urls) {
|
|
await addToMemoryTable(url, userContextId).catch(Cu.reportError);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* Registers a tab as open.
|
|
* @param {string} url Address of the tab
|
|
* @param {integer} userContextId Containers user context id
|
|
* @param {boolean} isInPrivateWindow In private browsing window or not
|
|
*/
|
|
static async registerOpenTab(url, userContextId, isInPrivateWindow) {
|
|
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
|
|
userContextId,
|
|
isInPrivateWindow
|
|
);
|
|
|
|
if (!UrlbarProviderOpenTabs._openTabs.has(userContextId)) {
|
|
UrlbarProviderOpenTabs._openTabs.set(userContextId, []);
|
|
}
|
|
UrlbarProviderOpenTabs._openTabs.get(userContextId).push(url);
|
|
await addToMemoryTable(url, userContextId).catch(Cu.reportError);
|
|
}
|
|
|
|
/**
|
|
* Unregisters a previously registered open tab.
|
|
* @param {string} url Address of the tab
|
|
* @param {integer} userContextId Containers user context id
|
|
* @param {boolean} isInPrivateWindow In private browsing window or not
|
|
*/
|
|
static async unregisterOpenTab(url, userContextId, isInPrivateWindow) {
|
|
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
|
|
userContextId,
|
|
isInPrivateWindow
|
|
);
|
|
|
|
let openTabs = UrlbarProviderOpenTabs._openTabs.get(userContextId);
|
|
if (openTabs) {
|
|
let index = openTabs.indexOf(url);
|
|
if (index != -1) {
|
|
openTabs.splice(index, 1);
|
|
await removeFromMemoryTable(url, userContextId).catch(Cu.reportError);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts querying.
|
|
* @param {object} queryContext The query context object
|
|
* @param {function} addCallback Callback invoked by the provider to add a new
|
|
* match.
|
|
* @returns {Promise} resolved when the query stops.
|
|
*/
|
|
async startQuery(queryContext, addCallback) {
|
|
// Note: this is not actually expected to be used as an internal provider,
|
|
// because normal history search will already coalesce with the open tabs
|
|
// temp table to return proper frecency.
|
|
// TODO:
|
|
// * properly search and handle tokens, this is just a mock for now.
|
|
let instance = this.queryInstance;
|
|
let conn = await PlacesUtils.promiseLargeCacheDBConnection();
|
|
await UrlbarProviderOpenTabs.promiseDBPopulated;
|
|
await conn.executeCached(
|
|
`
|
|
SELECT url, userContextId
|
|
FROM moz_openpages_temp
|
|
`,
|
|
{},
|
|
(row, cancel) => {
|
|
if (instance != this.queryInstance) {
|
|
cancel();
|
|
return;
|
|
}
|
|
addCallback(
|
|
this,
|
|
new UrlbarResult(
|
|
UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
|
|
UrlbarUtils.RESULT_SOURCE.TABS,
|
|
{
|
|
url: row.getResultByName("url"),
|
|
userContextId: row.getResultByName("userContextId"),
|
|
}
|
|
)
|
|
);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds an open page to the memory table.
|
|
* @param {string} url Address of the page
|
|
* @param {number} userContextId Containers user context id
|
|
* @returns {Promise} resolved after the addition.
|
|
*/
|
|
async function addToMemoryTable(url, userContextId) {
|
|
if (!UrlbarProviderOpenTabs.memoryTableInitialized) {
|
|
return;
|
|
}
|
|
await UrlbarProvidersManager.runInCriticalSection(async () => {
|
|
let conn = await PlacesUtils.promiseLargeCacheDBConnection();
|
|
await conn.executeCached(
|
|
`
|
|
INSERT OR REPLACE INTO moz_openpages_temp (url, userContextId, open_count)
|
|
VALUES ( :url,
|
|
:userContextId,
|
|
IFNULL( ( SELECT open_count + 1
|
|
FROM moz_openpages_temp
|
|
WHERE url = :url
|
|
AND userContextId = :userContextId ),
|
|
1
|
|
)
|
|
)
|
|
`,
|
|
{ url, userContextId }
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes an open page from the memory table.
|
|
* @param {string} url Address of the page
|
|
* @param {number} userContextId Containers user context id
|
|
* @returns {Promise} resolved after the removal.
|
|
*/
|
|
async function removeFromMemoryTable(url, userContextId) {
|
|
if (!UrlbarProviderOpenTabs.memoryTableInitialized) {
|
|
return;
|
|
}
|
|
await UrlbarProvidersManager.runInCriticalSection(async () => {
|
|
let conn = await PlacesUtils.promiseLargeCacheDBConnection();
|
|
await conn.executeCached(
|
|
`
|
|
UPDATE moz_openpages_temp
|
|
SET open_count = open_count - 1
|
|
WHERE url = :url
|
|
AND userContextId = :userContextId
|
|
`,
|
|
{ url, userContextId }
|
|
);
|
|
});
|
|
}
|