mirror of
https://github.com/zen-browser/desktop.git
synced 2025-09-29 22:48:39 +00:00
feat: Add learning for omnibox commands, b=no-bug, c=common
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||||
index 3c179db3b310c43f8c6c06b1ecbcf5ed59feefe6..693bef15401cd4428c8a0222de57b83b78564194 100644
|
index 3c179db3b310c43f8c6c06b1ecbcf5ed59feefe6..d9d2ce116ebcee8d403e165066c3a569bb952cd2 100644
|
||||||
--- a/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
--- a/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||||
+++ b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
+++ b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||||
@@ -719,6 +719,7 @@ function makeResultGroups({ showSearchSuggestionsFirst }) {
|
@@ -719,6 +719,7 @@ function makeResultGroups({ showSearchSuggestionsFirst }) {
|
||||||
*/
|
*/
|
||||||
let rootGroup = {
|
let rootGroup = {
|
||||||
children: [
|
children: [
|
||||||
+ { group: lazy.UrlbarUtils.RESULT_GROUP.ZEN_ACTION },
|
+ { children: [{ group: lazy.UrlbarUtils.RESULT_GROUP.ZEN_ACTION }] },
|
||||||
// heuristic
|
// heuristic
|
||||||
{
|
{
|
||||||
maxResultCount: 1,
|
maxResultCount: 1,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/urlbar/UrlbarUtils.sys.mjs b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
diff --git a/browser/components/urlbar/UrlbarUtils.sys.mjs b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||||
index 0bc15c02f56dd8f46a21fed02b4e21a741f27f41..b69a4d34f700637bd352620c520b989cf00fa39f 100644
|
index 0bc15c02f56dd8f46a21fed02b4e21a741f27f41..3b2c1218532dcbd79d5c970ab9fd075d4e58d1ff 100644
|
||||||
--- a/browser/components/urlbar/UrlbarUtils.sys.mjs
|
--- a/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||||
+++ b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
+++ b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||||
@@ -75,6 +75,7 @@ export var UrlbarUtils = {
|
@@ -75,6 +75,7 @@ export var UrlbarUtils = {
|
||||||
@@ -10,12 +10,12 @@ index 0bc15c02f56dd8f46a21fed02b4e21a741f27f41..b69a4d34f700637bd352620c520b989c
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// Defines provider types.
|
// Defines provider types.
|
||||||
@@ -576,6 +577,8 @@ export var UrlbarUtils = {
|
@@ -553,6 +554,8 @@ export var UrlbarUtils = {
|
||||||
return this.RESULT_GROUP.INPUT_HISTORY;
|
return this.RESULT_GROUP.HEURISTIC_SEARCH_TIP;
|
||||||
case "UrlbarProviderQuickSuggest":
|
case "HistoryUrlHeuristic":
|
||||||
return this.RESULT_GROUP.GENERAL_PARENT;
|
return this.RESULT_GROUP.HEURISTIC_HISTORY_URL;
|
||||||
+ case "ZenUrlbarProviderGlobalActions":
|
+ case "ZenUrlbarProviderGlobalActions":
|
||||||
+ return this.RESULT_GROUP.ZEN_ACTION;
|
+ return this.RESULT_GROUP.ZEN_ACTION;
|
||||||
default:
|
default:
|
||||||
break;
|
if (result.providerName.startsWith("TestProvider")) {
|
||||||
}
|
return this.RESULT_GROUP.HEURISTIC_TEST;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/urlbar/UrlbarView.sys.mjs b/browser/components/urlbar/UrlbarView.sys.mjs
|
diff --git a/browser/components/urlbar/UrlbarView.sys.mjs b/browser/components/urlbar/UrlbarView.sys.mjs
|
||||||
index fdbab8806fd320f4aacec46a42c8ef953580d00c..e23fae0d7e0b71d74899c11c229359864cd7e427 100644
|
index fdbab8806fd320f4aacec46a42c8ef953580d00c..031a615ad09274c578184b129434bbd93b49353d 100644
|
||||||
--- a/browser/components/urlbar/UrlbarView.sys.mjs
|
--- a/browser/components/urlbar/UrlbarView.sys.mjs
|
||||||
+++ b/browser/components/urlbar/UrlbarView.sys.mjs
|
+++ b/browser/components/urlbar/UrlbarView.sys.mjs
|
||||||
@@ -613,7 +613,7 @@ export class UrlbarView {
|
@@ -613,7 +613,7 @@ export class UrlbarView {
|
||||||
@@ -11,39 +11,7 @@ index fdbab8806fd320f4aacec46a42c8ef953580d00c..e23fae0d7e0b71d74899c11c22935986
|
|||||||
// Try to reuse the cached top-sites context. If it's not cached, then
|
// Try to reuse the cached top-sites context. If it's not cached, then
|
||||||
// there will be a gap of time between when the input is focused and
|
// there will be a gap of time between when the input is focused and
|
||||||
// when the view opens that can be perceived as flicker.
|
// when the view opens that can be perceived as flicker.
|
||||||
@@ -824,6 +824,31 @@ export class UrlbarView {
|
@@ -2706,6 +2706,8 @@ export class UrlbarView {
|
||||||
// still associated with the first result.
|
|
||||||
this.input.setResultForCurrentValue(firstResult);
|
|
||||||
}
|
|
||||||
+ if (queryContext.results[0].payload.zenAction) {
|
|
||||||
+ this.#selectElement(this.getFirstSelectableElement(), {
|
|
||||||
+ updateInput: false,
|
|
||||||
+ setAccessibleFocus:
|
|
||||||
+ this.controller._userSelectionBehavior == "arrow",
|
|
||||||
+ });
|
|
||||||
+ this.window.setTimeout(() => {
|
|
||||||
+ this.window.setTimeout(() => {
|
|
||||||
+ this.#selectElement(this.getFirstSelectableElement(), {
|
|
||||||
+ updateInput: false,
|
|
||||||
+ setAccessibleFocus:
|
|
||||||
+ this.controller._userSelectionBehavior == "arrow",
|
|
||||||
+ });
|
|
||||||
+ });
|
|
||||||
+ });
|
|
||||||
+ }
|
|
||||||
+ this.window.setTimeout(() => {
|
|
||||||
+ if (queryContext.results[0].payload.zenAction) {
|
|
||||||
+ this.#selectElement(this.getFirstSelectableElement(), {
|
|
||||||
+ updateInput: false,
|
|
||||||
+ setAccessibleFocus:
|
|
||||||
+ this.controller._userSelectionBehavior == "arrow",
|
|
||||||
+ });
|
|
||||||
+ }
|
|
||||||
+ }, 220);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Announce tab-to-search results to screen readers as the user types.
|
|
||||||
@@ -2706,6 +2731,8 @@ export class UrlbarView {
|
|
||||||
if (row?.hasAttribute("row-selectable")) {
|
if (row?.hasAttribute("row-selectable")) {
|
||||||
row?.toggleAttribute("selected", true);
|
row?.toggleAttribute("selected", true);
|
||||||
}
|
}
|
||||||
@@ -52,7 +20,7 @@ index fdbab8806fd320f4aacec46a42c8ef953580d00c..e23fae0d7e0b71d74899c11c22935986
|
|||||||
if (element != row) {
|
if (element != row) {
|
||||||
row?.toggleAttribute("descendant-selected", true);
|
row?.toggleAttribute("descendant-selected", true);
|
||||||
}
|
}
|
||||||
@@ -3189,7 +3216,7 @@ export class UrlbarView {
|
@@ -3189,7 +3191,7 @@ export class UrlbarView {
|
||||||
}
|
}
|
||||||
|
|
||||||
#enableOrDisableRowWrap() {
|
#enableOrDisableRowWrap() {
|
||||||
|
@@ -627,6 +627,7 @@
|
|||||||
|
|
||||||
& .urlbarView-favicon {
|
& .urlbarView-favicon {
|
||||||
fill: currentColor !important;
|
fill: currentColor !important;
|
||||||
|
stroke: currentColor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .urlbarView-shortcutContent {
|
& .urlbarView-shortcutContent {
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
import { XPCOMUtils } from 'resource://gre/modules/XPCOMUtils.sys.mjs';
|
import { XPCOMUtils } from 'resource://gre/modules/XPCOMUtils.sys.mjs';
|
||||||
import { UrlbarProvider, UrlbarUtils } from 'resource:///modules/UrlbarUtils.sys.mjs';
|
import { UrlbarProvider, UrlbarUtils } from 'resource:///modules/UrlbarUtils.sys.mjs';
|
||||||
import { globalActions } from 'resource:///modules/ZenUBGlobalActions.sys.mjs';
|
import { globalActions } from 'resource:///modules/ZenUBGlobalActions.sys.mjs';
|
||||||
|
import { zenUrlbarResultsLearner } from './ZenUBResultsLearner.sys.mjs';
|
||||||
|
|
||||||
const lazy = {};
|
const lazy = {};
|
||||||
|
|
||||||
@@ -14,14 +15,13 @@ const DYNAMIC_TYPE_NAME = 'zen-actions';
|
|||||||
const MAX_RECENT_ACTIONS = 5;
|
const MAX_RECENT_ACTIONS = 5;
|
||||||
const MINIMUM_QUERY_SCORE = 92;
|
const MINIMUM_QUERY_SCORE = 92;
|
||||||
|
|
||||||
const EN_LOCALE_MATCH = /^en(-.*)$/;
|
|
||||||
|
|
||||||
ChromeUtils.defineESModuleGetters(lazy, {
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
UrlbarResult: 'resource:///modules/UrlbarResult.sys.mjs',
|
UrlbarResult: 'resource:///modules/UrlbarResult.sys.mjs',
|
||||||
UrlbarTokenizer: 'resource:///modules/UrlbarTokenizer.sys.mjs',
|
UrlbarTokenizer: 'resource:///modules/UrlbarTokenizer.sys.mjs',
|
||||||
QueryScorer: 'resource:///modules/UrlbarProviderInterventions.sys.mjs',
|
QueryScorer: 'resource:///modules/UrlbarProviderInterventions.sys.mjs',
|
||||||
BrowserWindowTracker: 'resource:///modules/BrowserWindowTracker.sys.mjs',
|
BrowserWindowTracker: 'resource:///modules/BrowserWindowTracker.sys.mjs',
|
||||||
AddonManager: 'resource://gre/modules/AddonManager.sys.mjs',
|
AddonManager: 'resource://gre/modules/AddonManager.sys.mjs',
|
||||||
|
zenUrlbarResultsLearner: 'resource:///modules/ZenUBResultsLearner.sys.mjs',
|
||||||
});
|
});
|
||||||
|
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
@@ -35,6 +35,8 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||||||
* A provider that lets the user view all available global actions for a query.
|
* A provider that lets the user view all available global actions for a query.
|
||||||
*/
|
*/
|
||||||
export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
||||||
|
#seenCommands = new Set();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
lazy.UrlbarResult.addDynamicResultType(DYNAMIC_TYPE_NAME);
|
lazy.UrlbarResult.addDynamicResultType(DYNAMIC_TYPE_NAME);
|
||||||
@@ -64,8 +66,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
queryContext.searchString &&
|
queryContext.searchString &&
|
||||||
queryContext.searchString.length < UrlbarUtils.MAX_TEXT_LENGTH &&
|
queryContext.searchString.length < UrlbarUtils.MAX_TEXT_LENGTH &&
|
||||||
queryContext.searchString.length > 2 &&
|
queryContext.searchString.length > 2 &&
|
||||||
!lazy.UrlbarTokenizer.REGEXP_LIKE_PROTOCOL.test(queryContext.searchString) &&
|
!lazy.UrlbarTokenizer.REGEXP_LIKE_PROTOCOL.test(queryContext.searchString)
|
||||||
EN_LOCALE_MATCH.test(Services.locale.appLocaleAsBCP47)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
prettyIcon: workspace.icon,
|
prettyIcon: workspace.icon,
|
||||||
accentColor,
|
accentColor,
|
||||||
},
|
},
|
||||||
|
commandId: `zen:workspace-${workspace.uuid}`,
|
||||||
icon: 'chrome://browser/skin/zen-icons/forward.svg',
|
icon: 'chrome://browser/skin/zen-icons/forward.svg',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -116,6 +118,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
return {
|
return {
|
||||||
icon: 'chrome://browser/skin/zen-icons/extension.svg',
|
icon: 'chrome://browser/skin/zen-icons/extension.svg',
|
||||||
label: 'Extension',
|
label: 'Extension',
|
||||||
|
commandId: `zen:extension-${addon.id}`,
|
||||||
extraPayload: {
|
extraPayload: {
|
||||||
extensionId: addon.id,
|
extensionId: addon.id,
|
||||||
prettyName: addon.name,
|
prettyName: addon.name,
|
||||||
@@ -227,6 +230,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ownerGlobal = lazy.BrowserWindowTracker.getTopWindow();
|
const ownerGlobal = lazy.BrowserWindowTracker.getTopWindow();
|
||||||
|
const finalResults = [];
|
||||||
for (const action of actionsResults) {
|
for (const action of actionsResults) {
|
||||||
const [payload, payloadHighlights] = lazy.UrlbarResult.payloadAndSimpleHighlights([], {
|
const [payload, payloadHighlights] = lazy.UrlbarResult.payloadAndSimpleHighlights([], {
|
||||||
suggestion: action.label,
|
suggestion: action.label,
|
||||||
@@ -235,7 +239,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
zenCommand: action.command,
|
zenCommand: action.command,
|
||||||
dynamicType: DYNAMIC_TYPE_NAME,
|
dynamicType: DYNAMIC_TYPE_NAME,
|
||||||
zenAction: true,
|
zenAction: true,
|
||||||
icon: action.icon || 'chrome://browser/skin/trending.svg',
|
icon: action.icon,
|
||||||
shortcutContent: ownerGlobal.gZenKeyboardShortcutsManager.getShortcutDisplayFromCommand(
|
shortcutContent: ownerGlobal.gZenKeyboardShortcutsManager.getShortcutDisplayFromCommand(
|
||||||
action.command
|
action.command
|
||||||
),
|
),
|
||||||
@@ -249,11 +253,18 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
payload,
|
payload,
|
||||||
payloadHighlights
|
payloadHighlights
|
||||||
);
|
);
|
||||||
if (typeof action.suggestedIndex === 'number') {
|
if (zenUrlbarResultsLearner.shouldPrioritize(action.commandId)) {
|
||||||
result.suggestedIndex = action.suggestedIndex;
|
result.heuristic = true;
|
||||||
|
} else {
|
||||||
|
result.suggestedIndex = zenUrlbarResultsLearner.getDeprioritizeIndex(action.commandId);
|
||||||
}
|
}
|
||||||
addCallback(this, result);
|
result.commandId = action.commandId;
|
||||||
|
this.#seenCommands.add(action.commandId);
|
||||||
|
finalResults.push(result);
|
||||||
}
|
}
|
||||||
|
zenUrlbarResultsLearner.sortCommandsByPriority(finalResults).forEach((result) => {
|
||||||
|
addCallback(this, result);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -362,6 +373,19 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSearchSessionEnd(_queryContext, _controller, details) {
|
||||||
|
// We should only record the execution if a result was actually used.
|
||||||
|
// Otherwise we would start de-prioritizing commands that were never used.
|
||||||
|
if (details?.result) {
|
||||||
|
let usedCommand = null;
|
||||||
|
if (details?.provider === this.name) {
|
||||||
|
usedCommand = details.result?.commandId;
|
||||||
|
}
|
||||||
|
zenUrlbarResultsLearner.recordExecution(usedCommand, [...this.#seenCommands]);
|
||||||
|
}
|
||||||
|
this.#seenCommands = new Set();
|
||||||
|
}
|
||||||
|
|
||||||
onEngagement(queryContext, controller, details) {
|
onEngagement(queryContext, controller, details) {
|
||||||
const result = details.result;
|
const result = details.result;
|
||||||
const payload = result.payload;
|
const payload = result.payload;
|
||||||
|
@@ -11,7 +11,6 @@ const globalActionsTemplate = [
|
|||||||
label: 'Toggle Compact Mode',
|
label: 'Toggle Compact Mode',
|
||||||
command: 'cmd_zenCompactModeToggle',
|
command: 'cmd_zenCompactModeToggle',
|
||||||
icon: 'chrome://browser/skin/zen-icons/sidebar.svg',
|
icon: 'chrome://browser/skin/zen-icons/sidebar.svg',
|
||||||
suggestedIndex: 0,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Open Theme Picker',
|
label: 'Open Theme Picker',
|
||||||
@@ -22,7 +21,6 @@ const globalActionsTemplate = [
|
|||||||
label: 'New Split View',
|
label: 'New Split View',
|
||||||
command: 'cmd_zenNewEmptySplit',
|
command: 'cmd_zenNewEmptySplit',
|
||||||
icon: 'chrome://browser/skin/zen-icons/split.svg',
|
icon: 'chrome://browser/skin/zen-icons/split.svg',
|
||||||
suggestedIndex: 0,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'New Folder',
|
label: 'New Folder',
|
||||||
@@ -33,7 +31,6 @@ const globalActionsTemplate = [
|
|||||||
label: 'Copy Current URL',
|
label: 'Copy Current URL',
|
||||||
command: 'cmd_zenCopyCurrentURL',
|
command: 'cmd_zenCopyCurrentURL',
|
||||||
icon: 'chrome://browser/skin/zen-icons/edit-copy.svg',
|
icon: 'chrome://browser/skin/zen-icons/edit-copy.svg',
|
||||||
suggestedIndex: 0,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Settings',
|
label: 'Settings',
|
||||||
@@ -89,7 +86,6 @@ const globalActionsTemplate = [
|
|||||||
label: 'Close Tab',
|
label: 'Close Tab',
|
||||||
command: 'cmd_close',
|
command: 'cmd_close',
|
||||||
icon: 'chrome://browser/skin/zen-icons/close.svg',
|
icon: 'chrome://browser/skin/zen-icons/close.svg',
|
||||||
suggestedIndex: 1,
|
|
||||||
isAvailable: (window) => {
|
isAvailable: (window) => {
|
||||||
return isNotEmptyTab(window);
|
return isNotEmptyTab(window);
|
||||||
},
|
},
|
||||||
@@ -121,13 +117,11 @@ const globalActionsTemplate = [
|
|||||||
isAvailable: (window) => {
|
isAvailable: (window) => {
|
||||||
return isNotEmptyTab(window);
|
return isNotEmptyTab(window);
|
||||||
},
|
},
|
||||||
suggestedIndex: 1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Toggle Tabs on right',
|
label: 'Toggle Tabs on right',
|
||||||
command: 'cmd_zenToggleTabsOnRight',
|
command: 'cmd_zenToggleTabsOnRight',
|
||||||
icon: 'chrome://browser/skin/zen-icons/sidebars-right.svg',
|
icon: 'chrome://browser/skin/zen-icons/sidebars-right.svg',
|
||||||
suggestedIndex: 1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Add to Essentials',
|
label: 'Add to Essentials',
|
||||||
@@ -139,14 +133,12 @@ const globalActionsTemplate = [
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: 'chrome://browser/skin/zen-icons/essential-add.svg',
|
icon: 'chrome://browser/skin/zen-icons/essential-add.svg',
|
||||||
suggestedIndex: 1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Remove from Essentials',
|
label: 'Remove from Essentials',
|
||||||
command: (window) => window.gZenPinnedTabManager.removeEssentials(window.gBrowser.selectedTab),
|
command: (window) => window.gZenPinnedTabManager.removeEssentials(window.gBrowser.selectedTab),
|
||||||
isAvailable: (window) => window.gBrowser.selectedTab.hasAttribute('zen-essential'),
|
isAvailable: (window) => window.gBrowser.selectedTab.hasAttribute('zen-essential'),
|
||||||
icon: 'chrome://browser/skin/zen-icons/essential-remove.svg',
|
icon: 'chrome://browser/skin/zen-icons/essential-remove.svg',
|
||||||
suggestedIndex: 1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Find in Page',
|
label: 'Find in Page',
|
||||||
@@ -155,13 +147,11 @@ const globalActionsTemplate = [
|
|||||||
isAvailable: (window) => {
|
isAvailable: (window) => {
|
||||||
return isNotEmptyTab(window);
|
return isNotEmptyTab(window);
|
||||||
},
|
},
|
||||||
suggestedIndex: 1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Manage Extensions',
|
label: 'Manage Extensions',
|
||||||
command: 'Tools:Addons',
|
command: 'Tools:Addons',
|
||||||
icon: 'chrome://browser/skin/zen-icons/extension.svg',
|
icon: 'chrome://browser/skin/zen-icons/extension.svg',
|
||||||
suggestedIndex: 1,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -169,6 +159,10 @@ export const globalActions = globalActionsTemplate.map((action) => ({
|
|||||||
isAvailable: (window) => {
|
isAvailable: (window) => {
|
||||||
return window.document.getElementById(action.command)?.getAttribute('disabled') !== 'true';
|
return window.document.getElementById(action.command)?.getAttribute('disabled') !== 'true';
|
||||||
},
|
},
|
||||||
|
commandId:
|
||||||
|
typeof action.command === 'string'
|
||||||
|
? action.command
|
||||||
|
: `zen:global-action-${action.label.toLowerCase().replace(/\s+/g, '-')}`,
|
||||||
extraPayload: {},
|
extraPayload: {},
|
||||||
...action,
|
...action,
|
||||||
}));
|
}));
|
||||||
|
108
src/zen/urlbar/ZenUBResultsLearner.sys.mjs
Normal file
108
src/zen/urlbar/ZenUBResultsLearner.sys.mjs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
import { XPCOMUtils } from 'resource://gre/modules/XPCOMUtils.sys.mjs';
|
||||||
|
|
||||||
|
const lazy = {};
|
||||||
|
|
||||||
|
const DEFAULT_DB_DATA = '{}';
|
||||||
|
const DEPRIORITIZE_MAX = -4;
|
||||||
|
const PRIORITIZE_MAX = 5;
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
lazy,
|
||||||
|
'database',
|
||||||
|
'zen.urlbar.suggestions-learner',
|
||||||
|
'DEFAULT_DB_DATA'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that manages the learning of URL bar results for commands,
|
||||||
|
* can be used for any ID that can be executed in the URL bar.
|
||||||
|
*
|
||||||
|
* The schema would be something like:
|
||||||
|
* {
|
||||||
|
* "<command id>": <priority number>,
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* If the current command is not on the list is because the user
|
||||||
|
* has *seen* the command but never executed it. If the number is
|
||||||
|
* less than -2, that means the user will most likely never use it.
|
||||||
|
*
|
||||||
|
* The priority number is incremented each time the command is executed.
|
||||||
|
*/
|
||||||
|
class ZenUrlbarResultsLearner {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
get database() {
|
||||||
|
try {
|
||||||
|
return JSON.parse(lazy.database);
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDatabase(db) {
|
||||||
|
Services.prefs.setStringPref(
|
||||||
|
'zen.urlbar.suggestions-learner',
|
||||||
|
JSON.stringify(db || DEFAULT_DB_DATA)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
recordExecution(commandId, seenCommands = []) {
|
||||||
|
const db = this.database;
|
||||||
|
if (commandId) {
|
||||||
|
const numberOfUsages = Math.min((db[commandId] || 0) + 1, PRIORITIZE_MAX);
|
||||||
|
db[commandId] = numberOfUsages;
|
||||||
|
}
|
||||||
|
for (const cmd of seenCommands) {
|
||||||
|
if (cmd !== commandId) {
|
||||||
|
if (!db[cmd]) {
|
||||||
|
db[cmd] = -1;
|
||||||
|
} else {
|
||||||
|
const newIndex = Math.max(db[cmd] - 1, DEPRIORITIZE_MAX);
|
||||||
|
db[cmd] = newIndex;
|
||||||
|
if (newIndex === 0) {
|
||||||
|
// Save some space by deleting commands that are not used
|
||||||
|
// and have a neutral score.
|
||||||
|
delete db[cmd];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.saveDatabase(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldPrioritize(commandId) {
|
||||||
|
if (!commandId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const db = this.database;
|
||||||
|
return !!db[commandId] && db[commandId] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeprioritizeIndex(commandId) {
|
||||||
|
if (!commandId) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const db = this.database;
|
||||||
|
if (db[commandId] < 0) {
|
||||||
|
return Math.abs(db[commandId]);
|
||||||
|
}
|
||||||
|
// This will most likely never run, since
|
||||||
|
// positive commands are prioritized.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the given commands by their priority in the database.
|
||||||
|
* @param {*} commands
|
||||||
|
*/
|
||||||
|
sortCommandsByPriority(commands) {
|
||||||
|
const db = this.database;
|
||||||
|
return commands.sort((a, b) => (db[b.commandId] || 0) - (db[a.commandId] || 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const zenUrlbarResultsLearner = new ZenUrlbarResultsLearner();
|
@@ -6,4 +6,5 @@ EXTRA_JS_MODULES += [
|
|||||||
"ZenUBActionsProvider.sys.mjs",
|
"ZenUBActionsProvider.sys.mjs",
|
||||||
"ZenUBGlobalActions.sys.mjs",
|
"ZenUBGlobalActions.sys.mjs",
|
||||||
"ZenUBProvider.sys.mjs",
|
"ZenUBProvider.sys.mjs",
|
||||||
|
"ZenUBResultsLearner.sys.mjs",
|
||||||
]
|
]
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
"brandShortName": "Zen",
|
"brandShortName": "Zen",
|
||||||
"brandFullName": "Zen Browser",
|
"brandFullName": "Zen Browser",
|
||||||
"release": {
|
"release": {
|
||||||
"displayVersion": "1.16.1b",
|
"displayVersion": "1.16.2b",
|
||||||
"github": {
|
"github": {
|
||||||
"repo": "zen-browser/desktop"
|
"repo": "zen-browser/desktop"
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user