I am trying to build a plugin that transcribes what I say into Google Docs. In many examples that I found, they use manfiest V2 and there is a background.html
that has a scripts like <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
and then running the google API. My problem is that I got confused about managing my manifest.josn
and foreground.js
files and how should I call for gapi. Here are my files:
manifest.js
{
"name": "Docs Live Transcriber Plugin",
"version": "1.0",
"description": "A plugin for voice dictation and voice functions for GDocs.",
"manifest_version": 3,
"author": "",
"icons": {
"128": "img/logo.png"
},
"permissions": [
"https://docs.google.com/document/",
"https://script.google.com/",
"identity",
"tabs",
"storage",
"management",
"notifications",
"unlimitedStorage"
],
"oauth2": {
"client_id": "",
"api_key": "",
"scopes": ["https://www.googleapis.com/auth/userinfo.email", "profile"],
"discovery_docs": ["https://docs.googleapis.com/$discovery/rest?version=v1"]
},
"content_scripts": [
{
"matches": ["https://docs.google.com/*"],
"js": ["foreground.js"]
}
],
"content_security_policy": {
"extension_pages": "script-src 'self' ; object-src 'self'"
},
"host_permissions": ["https://www.googleapis.com/*"]
}
foreground.js
const createButton = (buttonId, eventListiner, innerText) => {
const button = document.createElement('button');
button.setAttribute('id', button_type);
button.setAttribute('onclick', eventListiner);
button.innerText = innerText;
return button;
};
const createScript = (link, load) => {
const script = document.createElement('script');
script.src = link;
script.setAttribute('defer', '');
script.setAttribute('async', '');
script.setAttribute('onload', load);
return script;
};
////////////////////// GAPI / GIS Initialization //////////////////////
const waitGAPI = createScript(
'https://apis.google.com/js/api.js',
'gapiLoaded()'
);
const waitGIS = createScript(
'https://apis.google.com/js/api.js',
'gapiLoaded()'
);
function gapiLoaded() {
gapi.load('client', initializeGapiClient);
}
async function initializeGapiClient() {
await gapi.client.init({
apiKey: API_KEY,
discoveryDocs: [DISCOVERY_DOC],
});
gapiInited = true;
maybeEnableButtons();
}
function gisLoaded() {
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: CLIENT_ID,
scope: SCOPES,
callback: '', // defined later
});
gisInited = true;
maybeEnableButtons();
}
const signIn = (e) => {
e.preventDefault();
chrome.identity.getAuthToken({ interactive: true }, (token) => {
if (chrome.runtime.lastError || !token) {
alert(
`SSO ended with an error: ${JSON.stringify(chrome.runtime.lastError)}`
);
return;
}
signInWithCredential(auth, GoogleAuthProvider.credential(null, token))
.then((res) => {
console.log('signed in!');
})
.catch((err) => {
alert(`SSO ended with an error: ${err}`);
});
});
};