fix: 6964
update icon when there is an taler action present
This commit is contained in:
parent
038dcbc9b7
commit
5e7be58658
@ -33,12 +33,12 @@
|
|||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"unlimitedStorage",
|
"unlimitedStorage",
|
||||||
|
"http://*/*",
|
||||||
|
"https://*/*",
|
||||||
"activeTab"
|
"activeTab"
|
||||||
],
|
],
|
||||||
"optional_permissions": [
|
"optional_permissions": [
|
||||||
"webRequest",
|
"webRequest"
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
],
|
],
|
||||||
"browser_action": {
|
"browser_action": {
|
||||||
"default_icon": {
|
"default_icon": {
|
||||||
@ -59,4 +59,4 @@
|
|||||||
"page": "static/background.html",
|
"page": "static/background.html",
|
||||||
"persistent": true
|
"persistent": true
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,6 +21,7 @@
|
|||||||
"unlimitedStorage",
|
"unlimitedStorage",
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"scripting",
|
"scripting",
|
||||||
|
"declarativeContent",
|
||||||
"alarms"
|
"alarms"
|
||||||
],
|
],
|
||||||
"commands": {
|
"commands": {
|
||||||
@ -55,4 +56,4 @@
|
|||||||
"background": {
|
"background": {
|
||||||
"service_worker": "dist/background.js"
|
"service_worker": "dist/background.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -46,7 +46,7 @@ export default api;
|
|||||||
const logger = new Logger("chrome.ts");
|
const logger = new Logger("chrome.ts");
|
||||||
|
|
||||||
function keepAlive(callback: any): void {
|
function keepAlive(callback: any): void {
|
||||||
if (chrome.runtime && chrome.runtime.getManifest().manifest_version === 3) {
|
if (extensionIsManifestV3()) {
|
||||||
chrome.alarms.create("wallet-worker", { periodInMinutes: 1 })
|
chrome.alarms.create("wallet-worker", { periodInMinutes: 1 })
|
||||||
|
|
||||||
chrome.alarms.onAlarm.addListener((a) => {
|
chrome.alarms.onAlarm.addListener((a) => {
|
||||||
@ -122,7 +122,7 @@ export async function removeHostPermissions(): Promise<boolean> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chrome.runtime && chrome.runtime.getManifest().manifest_version === 3) {
|
if (extensionIsManifestV3()) {
|
||||||
// Trying to remove host permissions with manifest >= v3 throws an error
|
// Trying to remove host permissions with manifest >= v3 throws an error
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ function getPermissionsApi(): CrossBrowserPermissionsApi {
|
|||||||
* @param callback function to be called
|
* @param callback function to be called
|
||||||
*/
|
*/
|
||||||
function notifyWhenAppIsReady(callback: () => void): void {
|
function notifyWhenAppIsReady(callback: () => void): void {
|
||||||
if (chrome.runtime && chrome.runtime.getManifest().manifest_version === 3) {
|
if (extensionIsManifestV3()) {
|
||||||
callback()
|
callback()
|
||||||
} else {
|
} else {
|
||||||
window.addEventListener("load", callback);
|
window.addEventListener("load", callback);
|
||||||
@ -356,21 +356,165 @@ function registerTalerHeaderListener(callback: (tabId: number, url: string) => v
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const alertIcons = {
|
||||||
|
"16": "/static/img/taler-alert-16.png",
|
||||||
|
"19": "/static/img/taler-alert-19.png",
|
||||||
|
"32": "/static/img/taler-alert-32.png",
|
||||||
|
"38": "/static/img/taler-alert-38.png",
|
||||||
|
"48": "/static/img/taler-alert-48.png",
|
||||||
|
"64": "/static/img/taler-alert-64.png",
|
||||||
|
"128": "/static/img/taler-alert-128.png",
|
||||||
|
"256": "/static/img/taler-alert-256.png",
|
||||||
|
"512": "/static/img/taler-alert-512.png"
|
||||||
|
}
|
||||||
|
const normalIcons = {
|
||||||
|
"16": "/static/img/taler-logo-16.png",
|
||||||
|
"19": "/static/img/taler-logo-19.png",
|
||||||
|
"32": "/static/img/taler-logo-32.png",
|
||||||
|
"38": "/static/img/taler-logo-38.png",
|
||||||
|
"48": "/static/img/taler-logo-48.png",
|
||||||
|
"64": "/static/img/taler-logo-64.png",
|
||||||
|
"128": "/static/img/taler-logo-128.png",
|
||||||
|
"256": "/static/img/taler-logo-256.png",
|
||||||
|
"512": "/static/img/taler-logo-512.png"
|
||||||
|
}
|
||||||
|
function setNormalIcon(): void {
|
||||||
|
if (extensionIsManifestV3()) {
|
||||||
|
chrome.action.setIcon({ path: normalIcons })
|
||||||
|
} else {
|
||||||
|
chrome.browserAction.setIcon({ path: normalIcons })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAlertedIcon(): void {
|
||||||
|
if (extensionIsManifestV3()) {
|
||||||
|
chrome.action.setIcon({ path: alertIcons })
|
||||||
|
} else {
|
||||||
|
chrome.browserAction.setIcon({ path: alertIcons })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface OffscreenCanvasRenderingContext2D extends CanvasState, CanvasTransform, CanvasCompositing, CanvasImageSmoothing, CanvasFillStrokeStyles, CanvasShadowStyles, CanvasFilters, CanvasRect, CanvasDrawPath, CanvasUserInterface, CanvasText, CanvasDrawImage, CanvasImageData, CanvasPathDrawingStyles, CanvasTextDrawingStyles, CanvasPath {
|
||||||
|
readonly canvas: OffscreenCanvas;
|
||||||
|
}
|
||||||
|
declare const OffscreenCanvasRenderingContext2D: {
|
||||||
|
prototype: OffscreenCanvasRenderingContext2D;
|
||||||
|
new(): OffscreenCanvasRenderingContext2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OffscreenCanvas extends EventTarget {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
getContext(contextId: "2d", contextAttributes?: CanvasRenderingContext2DSettings): OffscreenCanvasRenderingContext2D | null;
|
||||||
|
}
|
||||||
|
declare const OffscreenCanvas: {
|
||||||
|
prototype: OffscreenCanvas;
|
||||||
|
new(width: number, height: number): OffscreenCanvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCanvas(size: number): OffscreenCanvas {
|
||||||
|
if (extensionIsManifestV3()) {
|
||||||
|
return new OffscreenCanvas(size, size)
|
||||||
|
} else {
|
||||||
|
const c = document.createElement("canvas")
|
||||||
|
c.height = size;
|
||||||
|
c.width = size;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function createImage(size: number, file: string): Promise<ImageData> {
|
||||||
|
const r = await fetch(file)
|
||||||
|
const b = await r.blob()
|
||||||
|
const image = await createImageBitmap(b)
|
||||||
|
const canvas = createCanvas(size);
|
||||||
|
const canvasContext = canvas.getContext('2d')!;
|
||||||
|
canvasContext.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
canvasContext.drawImage(image, 0, 0, canvas.width, canvas.height);
|
||||||
|
const imageData = canvasContext.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
return imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerIconChangeOnTalerContent(): Promise<void> {
|
||||||
|
const imgs = await Promise.all(Object.entries(alertIcons).map(([key, value]) => createImage(parseInt(key, 10), value)))
|
||||||
|
const imageData = imgs.reduce((prev, cur) => ({ ...prev, [cur.width]: cur }), {} as { [size: string]: ImageData })
|
||||||
|
|
||||||
|
if (chrome.declarativeContent) {
|
||||||
|
// using declarative content does not need host permission
|
||||||
|
// and is faster
|
||||||
|
const secureTalerUrlLookup = {
|
||||||
|
conditions: [
|
||||||
|
new chrome.declarativeContent.PageStateMatcher({
|
||||||
|
css: ["a[href^='taler://'"]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
actions: [new chrome.declarativeContent.SetIcon({ imageData })]
|
||||||
|
};
|
||||||
|
const inSecureTalerUrlLookup = {
|
||||||
|
conditions: [
|
||||||
|
new chrome.declarativeContent.PageStateMatcher({
|
||||||
|
css: ["a[href^='taler+http://'"]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
actions: [new chrome.declarativeContent.SetIcon({ imageData })]
|
||||||
|
};
|
||||||
|
chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
|
||||||
|
chrome.declarativeContent.onPageChanged.addRules([secureTalerUrlLookup, inSecureTalerUrlLookup]);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this browser doesn't have declarativeContent
|
||||||
|
//we need host_permission and we will check the content for changing the icon
|
||||||
|
chrome.tabs.onUpdated.addListener(async (tabId, info: chrome.tabs.TabChangeInfo) => {
|
||||||
|
if (tabId < 0) return;
|
||||||
|
logger.info("tab updated", tabId, info);
|
||||||
|
if (info.status !== "complete") return;
|
||||||
|
const uri = await findTalerUriInTab(tabId);
|
||||||
|
console.log("urio", uri)
|
||||||
|
if (uri) {
|
||||||
|
setAlertedIcon()
|
||||||
|
} else {
|
||||||
|
setNormalIcon()
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
chrome.tabs.onActivated.addListener(async ({ tabId }: chrome.tabs.TabActiveInfo) => {
|
||||||
|
if (tabId < 0) return;
|
||||||
|
logger.info("tab activated", tabId);
|
||||||
|
const uri = await findTalerUriInTab(tabId);
|
||||||
|
console.log("urio", uri)
|
||||||
|
if (uri) {
|
||||||
|
setAlertedIcon()
|
||||||
|
} else {
|
||||||
|
setNormalIcon()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function registerOnInstalled(callback: () => void): void {
|
function registerOnInstalled(callback: () => void): void {
|
||||||
// This needs to be outside of main, as Firefox won't fire the event if
|
// This needs to be outside of main, as Firefox won't fire the event if
|
||||||
// the listener isn't created synchronously on loading the backend.
|
// the listener isn't created synchronously on loading the backend.
|
||||||
chrome.runtime.onInstalled.addListener((details) => {
|
chrome.runtime.onInstalled.addListener(async (details) => {
|
||||||
console.log(`onInstalled with reason: "${details.reason}"`);
|
logger.info(`onInstalled with reason: "${details.reason}"`);
|
||||||
if (details.reason === chrome.runtime.OnInstalledReason.INSTALL) {
|
if (details.reason === chrome.runtime.OnInstalledReason.INSTALL) {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
|
registerIconChangeOnTalerContent()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function useServiceWorkerAsBackgroundProcess(): boolean {
|
function extensionIsManifestV3(): boolean {
|
||||||
return chrome.runtime.getManifest().manifest_version === 3
|
return chrome.runtime.getManifest().manifest_version === 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useServiceWorkerAsBackgroundProcess(): boolean {
|
||||||
|
return extensionIsManifestV3()
|
||||||
|
}
|
||||||
|
|
||||||
function searchForTalerLinks(): string | undefined {
|
function searchForTalerLinks(): string | undefined {
|
||||||
let found;
|
let found;
|
||||||
found = document.querySelector("a[href^='taler://'")
|
found = document.querySelector("a[href^='taler://'")
|
||||||
@ -382,45 +526,59 @@ function searchForTalerLinks(): string | undefined {
|
|||||||
|
|
||||||
async function getCurrentTab(): Promise<chrome.tabs.Tab> {
|
async function getCurrentTab(): Promise<chrome.tabs.Tab> {
|
||||||
const queryOptions = { active: true, currentWindow: true };
|
const queryOptions = { active: true, currentWindow: true };
|
||||||
const [tab] = await chrome.tabs.query(queryOptions);
|
return new Promise<chrome.tabs.Tab>((resolve, reject) => {
|
||||||
return tab;
|
chrome.tabs.query(queryOptions, (tabs) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
reject(chrome.runtime.lastError)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(tabs[0])
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function findTalerUriInTab(tabId: number): Promise<string | undefined> {
|
||||||
|
if (extensionIsManifestV3()) {
|
||||||
|
// manifest v3
|
||||||
|
try {
|
||||||
|
const res = await chrome.scripting.executeScript({
|
||||||
|
target: { tabId, allFrames: true },
|
||||||
|
func: searchForTalerLinks,
|
||||||
|
args: []
|
||||||
|
})
|
||||||
|
return res[0].result
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
//manifest v2
|
||||||
|
chrome.tabs.executeScript(tabId,
|
||||||
|
{
|
||||||
|
code: `
|
||||||
|
(() => {
|
||||||
|
let x = document.querySelector("a[href^='taler://'") || document.querySelector("a[href^='taler+http://'");
|
||||||
|
return x ? x.href.toString() : null;
|
||||||
|
})();
|
||||||
|
`,
|
||||||
|
allFrames: false,
|
||||||
|
},
|
||||||
|
(result) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
console.error(JSON.stringify(chrome.runtime.lastError));
|
||||||
|
resolve(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(result[0]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
||||||
if (chrome.runtime.getManifest().manifest_version === 3) {
|
const tab = await getCurrentTab();
|
||||||
// manifest v3
|
if (!tab || tab.id === undefined) return;
|
||||||
const tab = await getCurrentTab();
|
return findTalerUriInTab(tab.id)
|
||||||
const res = await chrome.scripting.executeScript({
|
|
||||||
target: {
|
|
||||||
tabId: tab.id!,
|
|
||||||
allFrames: true,
|
|
||||||
} as any,
|
|
||||||
func: searchForTalerLinks,
|
|
||||||
args: []
|
|
||||||
})
|
|
||||||
return res[0].result
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
//manifest v2
|
|
||||||
chrome.tabs.executeScript(
|
|
||||||
{
|
|
||||||
code: `
|
|
||||||
(() => {
|
|
||||||
let x = document.querySelector("a[href^='taler://'") || document.querySelector("a[href^='taler+http://'");
|
|
||||||
return x ? x.href.toString() : null;
|
|
||||||
})();
|
|
||||||
`,
|
|
||||||
allFrames: false,
|
|
||||||
},
|
|
||||||
(result) => {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
console.error(JSON.stringify(chrome.runtime.lastError));
|
|
||||||
resolve(undefined);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(result[0]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user