fix: chrome.action
API registration (#40500)
This commit is contained in:
parent
cf5f0419f1
commit
7981d955b8
11 changed files with 536 additions and 1 deletions
|
@ -11,6 +11,7 @@ assert(enable_extensions,
|
|||
|
||||
function_registration("api_registration") {
|
||||
sources = [
|
||||
"//electron/shell/common/extensions/api/action.json",
|
||||
"//electron/shell/common/extensions/api/extension.json",
|
||||
"//electron/shell/common/extensions/api/resources_private.idl",
|
||||
"//electron/shell/common/extensions/api/scripting.idl",
|
||||
|
|
|
@ -38,6 +38,7 @@ group("extensions_features") {
|
|||
generated_json_strings("generated_api_json_strings") {
|
||||
sources = [
|
||||
"action.json",
|
||||
"browser_action.json",
|
||||
"extension.json",
|
||||
"resources_private.idl",
|
||||
"scripting.idl",
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
{
|
||||
"action": {
|
||||
"dependencies": ["manifest:action"],
|
||||
"contexts": ["blessed_extension"]
|
||||
},
|
||||
"action.isEnabled": {
|
||||
"channel": "stable"
|
||||
},
|
||||
"action.getBadgeTextColor": {
|
||||
"channel": "stable"
|
||||
},
|
||||
"action.setBadgeTextColor": {
|
||||
"channel": "stable"
|
||||
},
|
||||
"tabs": {
|
||||
"channel": "stable",
|
||||
"extension_types": ["extension"],
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
// well as feature.h, simple_feature.h, and feature_provider.h.
|
||||
|
||||
{
|
||||
"action": {
|
||||
"channel": "stable",
|
||||
"extension_types": ["extension"],
|
||||
"min_manifest_version": 3
|
||||
},
|
||||
"author": {
|
||||
"channel": "stable",
|
||||
"extension_types": "all"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"namespace": "action",
|
||||
"description": "Use the <code>chrome.action</code> API to control the extension's icon in the Google Chrome toolbar.",
|
||||
"compiler_options": {
|
||||
"implemented_in": "shell/browser/extensions/api/extension_action/extension_action_api.h"
|
||||
"implemented_in": "electron/shell/browser/extensions/api/extension_action/extension_action_api.h"
|
||||
},
|
||||
"types": [
|
||||
{
|
||||
|
|
370
shell/common/extensions/api/browser_action.json
Normal file
370
shell/common/extensions/api/browser_action.json
Normal file
|
@ -0,0 +1,370 @@
|
|||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
[
|
||||
{
|
||||
"namespace": "browserAction",
|
||||
"description": "Use browser actions to put icons in the main Google Chrome toolbar, to the right of the address bar. In addition to its <a href='browserAction#icon'>icon</a>, a browser action can have a <a href='browserAction#tooltip'>tooltip</a>, a <a href='browserAction#badge'>badge</a>, and a <a href='browserAction#popups'>popup</a>.",
|
||||
"compiler_options": {
|
||||
"implemented_in": "electron/shell/browser/extensions/api/extension_action/extension_action_api.h"
|
||||
},
|
||||
"types": [
|
||||
{
|
||||
"id": "ColorArray",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"minItems": 4,
|
||||
"maxItems": 4
|
||||
},
|
||||
{
|
||||
"id": "ImageDataType",
|
||||
"type": "object",
|
||||
"isInstanceOf": "ImageData",
|
||||
"additionalProperties": {
|
||||
"type": "any"
|
||||
},
|
||||
"description": "Pixel data for an image. Must be an ImageData object; for example, from a <code>canvas</code> element."
|
||||
},
|
||||
{
|
||||
"id": "TabDetails",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"minimum": 0,
|
||||
"description": "The ID of the tab to query state for. If no tab is specified, the non-tab-specific state is returned."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "setTitle",
|
||||
"type": "function",
|
||||
"description": "Sets the title of the browser action. This title appears in the tooltip.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "The string the browser action should display when moused over."
|
||||
},
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getTitle",
|
||||
"type": "function",
|
||||
"description": "Gets the title of the browser action.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"$ref": "TabDetails"
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "result",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "setIcon",
|
||||
"type": "function",
|
||||
"description": "Sets the icon for the browser action. The icon can be specified as the path to an image file, as the pixel data from a canvas element, or as a dictionary of one of those. Either the <code>path</code> or the <code>imageData</code> property must be specified.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"imageData": {
|
||||
"choices": [
|
||||
{
|
||||
"$ref": "ImageDataType"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "any"
|
||||
}
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"description": "Either an ImageData object or a dictionary {size -> ImageData} representing an icon to be set. If the icon is specified as a dictionary, the image used is chosen depending on the screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then an image with size <code>scale</code> * n is selected, where <i>n</i> is the size of the icon in the UI. At least one image must be specified. Note that 'details.imageData = foo' is equivalent to 'details.imageData = {'16': foo}'"
|
||||
},
|
||||
"path": {
|
||||
"choices": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "any"
|
||||
}
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"description": "Either a relative image path or a dictionary {size -> relative image path} pointing to an icon to be set. If the icon is specified as a dictionary, the image used is chosen depending on the screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then an image with size <code>scale</code> * n is selected, where <i>n</i> is the size of the icon in the UI. At least one image must be specified. Note that 'details.path = foo' is equivalent to 'details.path = {'16': foo}'"
|
||||
},
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"optional": true,
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "setPopup",
|
||||
"type": "function",
|
||||
"description": "Sets the HTML document to be opened as a popup when the user clicks the browser action icon.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"minimum": 0,
|
||||
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
|
||||
},
|
||||
"popup": {
|
||||
"type": "string",
|
||||
"description": "The relative path to the HTML file to show in a popup. If set to the empty string (<code>''</code>), no popup is shown."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getPopup",
|
||||
"type": "function",
|
||||
"description": "Gets the HTML document that is set as the popup for this browser action.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"$ref": "TabDetails"
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "result",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "setBadgeText",
|
||||
"type": "function",
|
||||
"description": "Sets the badge text for the browser action. The badge is displayed on top of the icon.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "Any number of characters can be passed, but only about four can fit into the space. If an empty string (<code>''</code>) is passed, the badge text is cleared. If <code>tabId</code> is specified and <code>text</code> is null, the text for the specified tab is cleared and defaults to the global badge text."
|
||||
},
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getBadgeText",
|
||||
"type": "function",
|
||||
"description": "Gets the badge text of the browser action. If no tab is specified, the non-tab-specific badge text is returned.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"$ref": "TabDetails"
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "result",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "setBadgeBackgroundColor",
|
||||
"type": "function",
|
||||
"description": "Sets the background color for the badge.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"color": {
|
||||
"description": "An array of four integers in the range 0-255 that make up the RGBA color of the badge. Can also be a string with a CSS hex color value; for example, <code>#FF0000</code> or <code>#F00</code> (red). Renders colors at full opacity.",
|
||||
"choices": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "ColorArray"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getBadgeBackgroundColor",
|
||||
"type": "function",
|
||||
"description": "Gets the background color of the browser action.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"$ref": "TabDetails"
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "result",
|
||||
"$ref": "ColorArray"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enable",
|
||||
"type": "function",
|
||||
"description": "Enables the browser action for a tab. Defaults to enabled.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"name": "tabId",
|
||||
"minimum": 0,
|
||||
"description": "The ID of the tab for which to modify the browser action."
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disable",
|
||||
"type": "function",
|
||||
"description": "Disables the browser action for a tab.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"name": "tabId",
|
||||
"minimum": 0,
|
||||
"description": "The ID of the tab for which to modify the browser action."
|
||||
}
|
||||
],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "openPopup",
|
||||
"type": "function",
|
||||
"description": "Opens the extension popup window in the active window but does not grant tab permissions.",
|
||||
"nodoc": true,
|
||||
"parameters": [],
|
||||
"returns_async": {
|
||||
"name": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "popupView",
|
||||
"type": "object",
|
||||
"optional": true,
|
||||
"description": "JavaScript 'window' object for the popup window if it was succesfully opened.",
|
||||
"additionalProperties": {
|
||||
"type": "any"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onClicked",
|
||||
"type": "function",
|
||||
"description": "Fired when a browser action icon is clicked. Does not fire if the browser action has a popup.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tab",
|
||||
"$ref": "tabs.Tab"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -898,6 +898,65 @@ describe('chrome extensions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// chrome.action is not supported in Electron. These tests only ensure
|
||||
// it does not explode.
|
||||
describe('chrome.action', () => {
|
||||
let customSession: Session;
|
||||
let w = null as unknown as BrowserWindow;
|
||||
|
||||
before(async () => {
|
||||
customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
||||
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-action-fail'));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
session: customSession
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('isEnabled', async () => {
|
||||
await w.loadURL(url);
|
||||
|
||||
const message = { method: 'isEnabled' };
|
||||
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
|
||||
|
||||
const [, , responseString] = await once(w.webContents, 'console-message');
|
||||
|
||||
const response = JSON.parse(responseString);
|
||||
expect(response).to.equal(false);
|
||||
});
|
||||
|
||||
it('setIcon', async () => {
|
||||
await w.loadURL(url);
|
||||
|
||||
const message = { method: 'setIcon' };
|
||||
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
|
||||
|
||||
const [, , responseString] = await once(w.webContents, 'console-message');
|
||||
|
||||
const response = JSON.parse(responseString);
|
||||
expect(response).to.equal(null);
|
||||
});
|
||||
|
||||
it('getBadgeText', async () => {
|
||||
await w.loadURL(url);
|
||||
|
||||
const message = { method: 'getBadgeText' };
|
||||
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
|
||||
|
||||
const [, , responseString] = await once(w.webContents, 'console-message');
|
||||
|
||||
const response = JSON.parse(responseString);
|
||||
expect(response).to.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('chrome.tabs', () => {
|
||||
let customSession: Session;
|
||||
let w = null as unknown as BrowserWindow;
|
||||
|
|
28
spec/fixtures/extensions/chrome-action-fail/background.js
vendored
Normal file
28
spec/fixtures/extensions/chrome-action-fail/background.js
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* global chrome */
|
||||
|
||||
const handleRequest = async (request, sender, sendResponse) => {
|
||||
const { method } = request;
|
||||
const tabId = sender.tab.id;
|
||||
|
||||
switch (method) {
|
||||
case 'isEnabled': {
|
||||
chrome.action.isEnabled(tabId).then(sendResponse);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'setIcon': {
|
||||
chrome.action.setIcon({ tabId, imageData: {} }).then(sendResponse);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'getBadgeText': {
|
||||
chrome.action.getBadgeText({ tabId }).then(sendResponse);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
handleRequest(request, sender, sendResponse);
|
||||
return true;
|
||||
});
|
30
spec/fixtures/extensions/chrome-action-fail/main.js
vendored
Normal file
30
spec/fixtures/extensions/chrome-action-fail/main.js
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* global chrome */
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
sendResponse(request);
|
||||
});
|
||||
|
||||
const testMap = {
|
||||
isEnabled () {
|
||||
chrome.runtime.sendMessage({ method: 'isEnabled' }, response => {
|
||||
console.log(JSON.stringify(response));
|
||||
});
|
||||
},
|
||||
setIcon () {
|
||||
chrome.runtime.sendMessage({ method: 'setIcon' }, response => {
|
||||
console.log(JSON.stringify(response));
|
||||
});
|
||||
},
|
||||
getBadgeText () {
|
||||
chrome.runtime.sendMessage({ method: 'getBadgeText' }, response => {
|
||||
console.log(JSON.stringify(response));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const dispatchTest = (event) => {
|
||||
const { method, args = [] } = JSON.parse(event.data);
|
||||
testMap[method](...args);
|
||||
};
|
||||
|
||||
window.addEventListener('message', dispatchTest, false);
|
19
spec/fixtures/extensions/chrome-action-fail/manifest.json
vendored
Normal file
19
spec/fixtures/extensions/chrome-action-fail/manifest.json
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Action popup demo",
|
||||
"version": "1.0",
|
||||
"manifest_version": 3,
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["main.js"],
|
||||
"run_at": "document_start"
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
"default_title": "Click Me",
|
||||
"default_popup": "popup.html"
|
||||
}
|
||||
}
|
9
spec/fixtures/extensions/chrome-action-fail/popup.html
vendored
Normal file
9
spec/fixtures/extensions/chrome-action-fail/popup.html
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
console.log('b');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in a new issue