mirror of
https://github.com/GoogleChrome/chrome-extensions-samples.git
synced 2026-03-26 13:19:49 +07:00
[New sample] Open Chrome API reference page (omnibox, alarms, messaging sample) (#848)
* First draft * Rename folder * Tweak comments * Update index.html * remove extra closing div * Rename sw file * Apply first round of @sebastianbenz suggestions * Fix import * Update popover * Second tech review round
This commit is contained in:
81
functional-samples/tutorial.open-api-reference/api-list.js
Normal file
81
functional-samples/tutorial.open-api-reference/api-list.js
Normal file
@@ -0,0 +1,81 @@
|
||||
export default [
|
||||
{
|
||||
content: 'commands',
|
||||
description:
|
||||
'Use the <match>Commands API</match> to add a keyboard shortcuts.'
|
||||
},
|
||||
{
|
||||
content: 'contextmenus',
|
||||
description:
|
||||
"Use the <match>ContextMenus API</match> to add a custom item to Chrome's context menu."
|
||||
},
|
||||
{
|
||||
content: 'declarativeNetRequest',
|
||||
description:
|
||||
'Use the <match>DeclarativeNetRequest API</match> to block or modify network requests.'
|
||||
},
|
||||
{
|
||||
content: 'downloads',
|
||||
description:
|
||||
'Use the <match>Downloads API</match> to programmatically manipulate downloads.'
|
||||
},
|
||||
{
|
||||
content: 'i18n',
|
||||
description: 'Use the <match>i18n API</match> to localize your extension'
|
||||
},
|
||||
{
|
||||
content: 'identity',
|
||||
description:
|
||||
'Use the <match>Identity API</match> to get OAuth2 access tokens.'
|
||||
},
|
||||
{
|
||||
content: 'notifications',
|
||||
description:
|
||||
'Use the <match>Notifications API</match> show notifications to users in the system tray.'
|
||||
},
|
||||
{
|
||||
content: 'offscreen',
|
||||
description:
|
||||
'Use the <match>Offscreen API</match> to create and manage offscreen documents.'
|
||||
},
|
||||
{
|
||||
content: 'omnibox',
|
||||
description:
|
||||
"Use the <match>Omnibox API</match> to register a keyword with Chrome's address bar."
|
||||
},
|
||||
{
|
||||
content: 'permissions',
|
||||
description:
|
||||
'Use the <match>Permissions API</match> to request optional permissions at run time.'
|
||||
},
|
||||
{
|
||||
content: 'runtime',
|
||||
description:
|
||||
'Use the <match>Runtime API</match> pass messages, manage extension lifecycle, and access other helper utils.'
|
||||
},
|
||||
{
|
||||
content: 'scripting',
|
||||
description:
|
||||
'Use the <match>Scripting API</match> to execute scripts in different contexts.'
|
||||
},
|
||||
{
|
||||
content: 'storage',
|
||||
description:
|
||||
'Use the <match>Storage API</match> to store, retrieve, and track changes to user data.'
|
||||
},
|
||||
{
|
||||
content: 'tabs',
|
||||
description:
|
||||
'Use the <match>Tabs API</match> to create, update and manipulate tabs.'
|
||||
},
|
||||
{
|
||||
content: 'topSites',
|
||||
description:
|
||||
'Use the <match>TopSites API</match> to access the most visited sites that are displayed on the new tab page.'
|
||||
},
|
||||
{
|
||||
content: 'webNavigation',
|
||||
description:
|
||||
'Use the <match>WebNavigation API</match> to receive notifications about the status of navigation requests in-flight.'
|
||||
}
|
||||
];
|
||||
30
functional-samples/tutorial.open-api-reference/content.js
Normal file
30
functional-samples/tutorial.open-api-reference/content.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// Popover API https://chromestatus.com/feature/5463833265045504
|
||||
|
||||
(async () => {
|
||||
const nav = document.querySelector('.navigation-rail__links');
|
||||
|
||||
const { tip } = await chrome.runtime.sendMessage({ greeting: 'tip' });
|
||||
|
||||
const tipWidget = createDomElement(`
|
||||
<button class="navigation-rail__link" popovertarget="tip-popover" popovertargetaction="show" style="padding: 0; border: none; background: none;>
|
||||
<div class="navigation-rail__icon">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d='M15 16H9M14.5 9C14.5 7.61929 13.3807 6.5 12 6.5M6 9C6 11.2208 7.2066 13.1599 9 14.1973V18.5C9 19.8807 10.1193 21 11.5 21H12.5C13.8807 21 15 19.8807 15 18.5V14.1973C16.7934 13.1599 18 11.2208 18 9C18 5.68629 15.3137 3 12 3C8.68629 3 6 5.68629 6 9Z'"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span>Tip</span>
|
||||
</button>
|
||||
`);
|
||||
|
||||
const popover = createDomElement(
|
||||
`<div id='tip-popover' popover>${tip}</div>`
|
||||
);
|
||||
|
||||
document.body.append(popover);
|
||||
nav.append(tipWidget);
|
||||
})();
|
||||
|
||||
function createDomElement(html) {
|
||||
const dom = new DOMParser().parseFromString(html, 'text/html');
|
||||
return dom.body.firstElementChild;
|
||||
}
|
||||
BIN
functional-samples/tutorial.open-api-reference/icon-128.png
Normal file
BIN
functional-samples/tutorial.open-api-reference/icon-128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
BIN
functional-samples/tutorial.open-api-reference/icon-16.png
Normal file
BIN
functional-samples/tutorial.open-api-reference/icon-16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
25
functional-samples/tutorial.open-api-reference/manifest.json
Normal file
25
functional-samples/tutorial.open-api-reference/manifest.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Open extension API reference",
|
||||
"version": "1.0.0",
|
||||
"icons": {
|
||||
"16": "icon-16.png",
|
||||
"128": "icon-128.png"
|
||||
},
|
||||
"background": {
|
||||
"service_worker": "service-worker.js",
|
||||
"type": "module"
|
||||
},
|
||||
"minimum_chrome_version": "102",
|
||||
"omnibox": {
|
||||
"keyword": "api"
|
||||
},
|
||||
"permissions": ["alarms", "storage"],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
|
||||
"js": ["content.js"]
|
||||
}
|
||||
],
|
||||
"host_permissions": ["https://extension-tips.glitch.me/*"]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import './sw-omnibox.js';
|
||||
import './sw-tips.js';
|
||||
37
functional-samples/tutorial.open-api-reference/sw-omnibox.js
Normal file
37
functional-samples/tutorial.open-api-reference/sw-omnibox.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { getApiSuggestions } from './sw-suggestions.js';
|
||||
|
||||
console.log('sw-omnibox.js');
|
||||
|
||||
// Initialize default API suggestions
|
||||
chrome.runtime.onInstalled.addListener(({ reason }) => {
|
||||
if (reason === 'install') {
|
||||
chrome.storage.local.set({
|
||||
apiSuggestions: ['tabs', 'storage', 'scripting']
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const URL_CHROME_EXTENSIONS_DOC =
|
||||
'https://developer.chrome.com/docs/extensions/reference/';
|
||||
const NUMBER_OF_PREVIOUS_SEARCHES = 4;
|
||||
|
||||
// Displays the suggestions after user starts typing
|
||||
chrome.omnibox.onInputChanged.addListener(async (input, suggest) => {
|
||||
const { description, suggestions } = await getApiSuggestions(input);
|
||||
await chrome.omnibox.setDefaultSuggestion({ description });
|
||||
suggest(suggestions);
|
||||
});
|
||||
|
||||
// Opens the reference page of the chosen API
|
||||
chrome.omnibox.onInputEntered.addListener((input) => {
|
||||
chrome.tabs.create({ url: URL_CHROME_EXTENSIONS_DOC + input });
|
||||
// Saves the latest keyword
|
||||
updateHistory(input);
|
||||
});
|
||||
|
||||
async function updateHistory(input) {
|
||||
const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
|
||||
apiSuggestions.unshift(input);
|
||||
apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
|
||||
await chrome.storage.local.set({ apiSuggestions });
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import apiList from './api-list.js';
|
||||
|
||||
/**
|
||||
* Returns a list of suggestions and a description for the default suggestion
|
||||
*/
|
||||
export async function getApiSuggestions(input) {
|
||||
const suggestions = apiList.filter((api) => api.content.startsWith(input));
|
||||
|
||||
// return suggestions if any exist
|
||||
if (suggestions.length) {
|
||||
return {
|
||||
description: 'Matching Chrome APIs',
|
||||
suggestions: suggestions
|
||||
};
|
||||
}
|
||||
|
||||
// return past searches if no match was found
|
||||
const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
|
||||
return {
|
||||
description: 'No matches found. Choose from past searches',
|
||||
suggestions: apiList.filter((item) => apiSuggestions.includes(item.content))
|
||||
};
|
||||
}
|
||||
28
functional-samples/tutorial.open-api-reference/sw-tips.js
Normal file
28
functional-samples/tutorial.open-api-reference/sw-tips.js
Normal file
@@ -0,0 +1,28 @@
|
||||
console.log('sw-tips.js');
|
||||
|
||||
// Fetch tip & save in storage
|
||||
const updateTip = async () => {
|
||||
const response = await fetch('https://extension-tips.glitch.me/tips.json');
|
||||
const tips = await response.json();
|
||||
const randomIndex = Math.floor(Math.random() * tips.length);
|
||||
await chrome.storage.local.set({ tip: tips[randomIndex] });
|
||||
};
|
||||
|
||||
// Create a daily alarm and retrieves the first tip when extension is installed.
|
||||
chrome.runtime.onInstalled.addListener(({ reason }) => {
|
||||
if (reason === 'install') {
|
||||
chrome.alarms.create({ delayInMinutes: 1, periodInMinutes: 1440 });
|
||||
updateTip();
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve tip of the day
|
||||
chrome.alarms.onAlarm.addListener(updateTip);
|
||||
|
||||
// Send tip to content script via messaging
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.greeting === 'tip') {
|
||||
chrome.storage.local.get('tip').then(sendResponse);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user