Make the search button reuse an open search tab if it exists
This commit is contained in:
parent
a5d7de8e97
commit
dbec4bffda
@ -152,8 +152,22 @@ async function apiCommandExec(command) {
|
||||
}
|
||||
}
|
||||
apiCommandExec.handlers = {
|
||||
search: () => {
|
||||
chrome.tabs.create({url: chrome.extension.getURL('/bg/search.html')});
|
||||
search: async () => {
|
||||
const url = chrome.extension.getURL('/bg/search.html');
|
||||
try {
|
||||
const tab = await apiFindTab(1000, (url2) => (
|
||||
url2 !== null &&
|
||||
url2.startsWith(url) &&
|
||||
(url2.length === url.length || url2[url.length] === '?' || url2[url.length] === '#')
|
||||
));
|
||||
if (tab !== null) {
|
||||
await apiFocusTab(tab);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
chrome.tabs.create({url});
|
||||
},
|
||||
|
||||
help: () => {
|
||||
@ -298,3 +312,74 @@ async function apiGetBrowser() {
|
||||
return 'chrome';
|
||||
}
|
||||
}
|
||||
|
||||
function apiGetTabUrl(tab) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => {
|
||||
let url = null;
|
||||
if (!chrome.runtime.lastError) {
|
||||
url = (response !== null && typeof response === 'object' && !Array.isArray(response) ? response.url : null);
|
||||
if (url !== null && typeof url !== 'string') {
|
||||
url = null;
|
||||
}
|
||||
}
|
||||
resolve({tab, url});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function apiFindTab(timeout, checkUrl) {
|
||||
// This function works around the need to have the "tabs" permission to access tab.url.
|
||||
const tabs = await new Promise((resolve) => chrome.tabs.query({}, resolve));
|
||||
let matchPromiseResolve = null;
|
||||
const matchPromise = new Promise((resolve) => { matchPromiseResolve = resolve; });
|
||||
|
||||
const checkTabUrl = ({tab, url}) => {
|
||||
if (checkUrl(url, tab)) {
|
||||
matchPromiseResolve(tab);
|
||||
}
|
||||
};
|
||||
|
||||
const promises = [];
|
||||
for (const tab of tabs) {
|
||||
const promise = apiGetTabUrl(tab);
|
||||
promise.then(checkTabUrl);
|
||||
promises.push(promise);
|
||||
}
|
||||
|
||||
const racePromises = [
|
||||
matchPromise,
|
||||
Promise.all(promises).then(() => null)
|
||||
];
|
||||
if (typeof timeout === 'number') {
|
||||
racePromises.push(new Promise((resolve) => setTimeout(() => resolve(null), timeout)));
|
||||
}
|
||||
|
||||
return await Promise.race(racePromises);
|
||||
}
|
||||
|
||||
async function apiFocusTab(tab) {
|
||||
const tabWindow = await new Promise((resolve) => {
|
||||
chrome.windows.get(tab.windowId, {}, (tabWindow) => {
|
||||
const e = chrome.runtime.lastError;
|
||||
if (e) { reject(e); }
|
||||
else { resolve(tabWindow); }
|
||||
});
|
||||
});
|
||||
if (!tabWindow.focused) {
|
||||
await new Promise((resolve, reject) => {
|
||||
chrome.windows.update(tab.windowId, {focused: true}, () => {
|
||||
const e = chrome.runtime.lastError;
|
||||
if (e) { reject(e); }
|
||||
else { resolve(); }
|
||||
});
|
||||
});
|
||||
}
|
||||
await new Promise((resolve, reject) => {
|
||||
chrome.tabs.update(tab.id, {active: true}, () => {
|
||||
const e = chrome.runtime.lastError;
|
||||
if (e) { reject(e); }
|
||||
else { resolve(); }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -114,6 +114,17 @@ class DisplaySearch extends Display {
|
||||
}
|
||||
}
|
||||
|
||||
onRuntimeMessage({action, params}, sender, callback) {
|
||||
const handlers = DisplaySearch.runtimeMessageHandlers;
|
||||
if (handlers.hasOwnProperty(action)) {
|
||||
const handler = handlers[action];
|
||||
const result = handler(this, params);
|
||||
callback(result);
|
||||
} else {
|
||||
return super.onRuntimeMessage({action, params}, sender, callback);
|
||||
}
|
||||
}
|
||||
|
||||
getOptionsContext() {
|
||||
return this.optionsContext;
|
||||
}
|
||||
@ -188,4 +199,10 @@ class DisplaySearch extends Display {
|
||||
}
|
||||
}
|
||||
|
||||
DisplaySearch.runtimeMessageHandlers = {
|
||||
getUrl: () => {
|
||||
return {url: window.location.href};
|
||||
}
|
||||
};
|
||||
|
||||
window.yomichan_search = DisplaySearch.create();
|
||||
|
@ -430,9 +430,14 @@ async function onOptionsUpdate({source}) {
|
||||
await formWrite(options);
|
||||
}
|
||||
|
||||
function onMessage({action, params}) {
|
||||
if (action === 'optionsUpdate') {
|
||||
onOptionsUpdate(params);
|
||||
function onMessage({action, params}, sender, callback) {
|
||||
switch (action) {
|
||||
case 'optionsUpdate':
|
||||
onOptionsUpdate(params);
|
||||
break;
|
||||
case 'getUrl':
|
||||
callback({url: window.location.href});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,8 +237,8 @@ class Frontend {
|
||||
const handlers = Frontend.runtimeMessageHandlers;
|
||||
if (handlers.hasOwnProperty(action)) {
|
||||
const handler = handlers[action];
|
||||
handler(this, params);
|
||||
callback();
|
||||
const result = handler(this, params);
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,5 +576,9 @@ Frontend.runtimeMessageHandlers = {
|
||||
|
||||
popupSetVisibleOverride: (self, {visible}) => {
|
||||
self.popup.setVisibleOverride(visible);
|
||||
},
|
||||
|
||||
getUrl: () => {
|
||||
return {url: window.location.href};
|
||||
}
|
||||
};
|
||||
|
@ -175,8 +175,8 @@ class Display {
|
||||
const handlers = Display.runtimeMessageHandlers;
|
||||
if (handlers.hasOwnProperty(action)) {
|
||||
const handler = handlers[action];
|
||||
handler(this, params);
|
||||
callback();
|
||||
const result = handler(this, params);
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user