Detect if Office Editing for Docs, Sheets & Slides is installed - google-chrome-extension

Is there a way to detect if
'Office Editing for Docs, Sheets & Slides'
is installed in Chrome from javascript running in a webpage (not in extension) ?
If it is installed, we want to open and edit the document in a new tab,
while if it is not installed, we want to download the document in CURRENT tab.

I just digged into the source code of this extension, and found it has the following entries in manifest.json
"web_accessible_resources": [ "views/app.html", "views/qowt.html" ]
So you can detect if the extension is installed by querying if views/app.html exists. Just make an ajax call and check the xhr status.
function detectExtension(extensionId, successCallback, failCallback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
successCallback();
} else {
failCallback();
}
}
};
xhr.open("GET", "chrome-extension://" + extensionId + "/views/app.html");
xhr.send();
}
detectExtension("gbkeegbaiigmenfmjfclcdgdpimamgkj", function() {
console.log("The extension is installed");
}, function() {
console.log("The extension is not installed");
});

Related

chrome extension always show "service worker inactive" after browser restart if manifest is MV3

i am using the latest chrome: Version 100.0.4896.60 (Official Build) (64-bit) on win 10 pro
when i install an extension all works fine.
when i close chrome and reopen, the extensions no long work.
the extensions tab shows for all extensions: "worker service (inactive)"
after click on the reload button of the extension all is ok.
i also tested it with:
https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/examples/hello-world
to make sure that this could be to some settings, i uninstalled chrome, removed all chrome files and reinstalled it.
the issue persists.
friends of mine do not seem to have this issue with the same chrome version.
any suggestions on how to resolve this ?
here the code:
"use strict";
async function sendRequest(request, sendResponse) {
try {
const startTime = Date.now();
const response = await fetch(request.url, request.options);
const time = Date.now() - startTime;
const body = await response.text();
const headers = [...response.headers].map((el) => ({
key: el[0],
value: el[1],
}));
sendResponse({
status: response.status,
body,
headers,
time,
});
} catch (err) {
sendResponse({
err: err.message
});
}
}
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
chrome.storage.sync.get("host", ({ host }) => {
if (host === sender.tab.url) {
if (request.type === "send-request") {
sendRequest(request, sendResponse);
} else if (request.type === "ping") {
sendResponse();
} else {
console.log("bad request type", request.type);
}
} else {
console.log("host not correct", host, sender.tab.url);
}
});
// NOTE: return value required to keep port open for async response
return true;
});
chrome.webNavigation.onBeforeNavigate.addListener(() => {
console.info("service is up 2");
});
chrome.webNavigation.onHistoryStateUpdated.addListener((details) => {
console.log('service is up');
});
This is a known bug. You can read more about it here: https://bugs.chromium.org/p/chromium/issues/detail?id=1271154#c52

node app download file from gcloud storage to client

Seems like this should have a canned answer of some sort, but I can't find anything.
The scenario is thus:
I have a web page that lists files to download
The files are located in gcloud storage
I have a node server (express) app to reach into gcloud and fetch the file.
The web page js looks like this:
<script>
function downloadFile(client, fn) {
var x=new XMLHttpRequest();
x.open("GET", "https://<domain>/fetch/" + client + '/' + fn, true);
x.responseType = 'blob';
x.onload=function(e){download(x.response, fn, "<content-type>" ); }
x.send();
}
</script>
It's doing a straight-up XMLHttpRequest() to the server with the requred fetch args.
The relevant part of the node js looks like this:
app.get('/fetch/:client/:filename', async function(req,rsp) {
try {
const storage = new Storage();
const fileLoc = req.params.client + '/' + req.params.filename
const options = {
destination: './' + req.params.filename,
};
// Downloads the file
let file = await storage
.bucket('<bucket-name>')
.file(fileLoc)
let rstream = await file.createReadStream()
.on("error", (err) => {
console.log(" --> rstream error: " + err)
})
.on("response", (strRsp) => {
console.log(' --> response received, sending headers.')
rsp.setHeader('Content-Length', strRsp.headers['content-length'])
rsp.setHeader('Content-Type', strRsp.headers['content-type'])
rsp.header('Content-Disposition', 'attachment; filename=' + req.params.filename)
})
.on("end", () => {
console.log(' --> end received.')
rsp.status(200).end()
return true
})
.pipe(rsp)
} catch(err) {
console.log('download error: ' + err)
rsp.status(400).send('failed')
}
});
The thing is that it works, but it downloads the entire file (silently) before it puts up the save-as dialog.
Is there a way to put up the save dialog before downloading? (Perhaps I need to do the 'content-disposition' header on the client side...?)
Barring that, is there a way to reflect progress back to the web page js so that I can put up a dialog and show progress and maybe a cancel button until it is done and shows the save-as dialog?
Ok, I went with the latter answer. Doing the following:
On download request, pop up a loading dialog with information about the download.
Register a progress callback with the XMLHttpRequest instance
Display the progress information in the dialog
Dialog has a 'Cancel' button which calls 'abort()' on the XMLHttpRequest instance
On completion (or abort) update the dialog and then close it via a timeout.

How to append to variable within http.get? (Node.JS)

var content = 'Hi, welcome to my webpage.';
var options = {host: 'www.website.com', path: '/folder/song.mp3', agent:false};
http.get(options, function(r) {
r.on('data', function() {
if (r.statusCode !== '404') {
content += 'Download';
}
});
});
fs.writeFile('index.html', content);
So normally, if I want to write a static html webpage from a node.js script, this works perfectly. For some reason, however, if I try to append to content from within http.get, it doesn't work. The whole point is to check if the file/page exists from an external website, and if it does then to display a link to it. The code that checks for the existing file works just fine, but I can't append anything to an external variable it seems. Any help would be much appreciated.
You need to use end event of http to indicate when you finish receiving data.
As node is asynchronouse the fs.writeFile instruction is run before all your data is received.
Here's how you can do it:
http.get(options, function(r) {
r.on('data', function() {
if (r.statusCode !== '404') {
content += 'Download';
}
});
r.on('end', function() {
fs.writeFile('index.html', content);
});
});

How can I receive message from onClick event of web page using chrome extension?

I want to catch click event from injected script on all tabs of chrome browser.
like below method
event.js is main javascript and test.js is injected js.
event.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
if (changeInfo.status === 'complete') {
chrome.tabs.executeScript(tabId, { file: 'test.js'}, function(){
console.log('executed');
});
}
});
test.js
var fragment = create('<div onClick="sendMessage to my extension">Hellow</div>');
document.body.insertBefore(fragment, document.body.childNodes[0]);
how can I receive message from other website to my extenstion?
Is it impossible?
Thanks for reading.
Assuming you are properly injecting test.js as a content script (e.g. by declaring the appropriate properties in your manifest.json), you need to make the following modifications:
In event.js add:
chrome.runtime.onMessage.addListener(function(msg, sender) {
console.log('Tab with ID ' + sender.tab.id + ' sent a message:\n' + msg.text);
});
In test.js replace your code with:
var mydiv = document.createElement('div');
mydiv.textContent = 'Hello';
mydiv.addEventListener('click', function() {
chrome.runtime.sendMessage({ text: 'Someone clicked my DIV !' });
});
document.body.insertBefore(mydiv, document.body.childNodes[0]);

Translating JavaScript bookmark into Chrome browser action extension

I want to create a Chrome extension with a browser action onClicked which provides the same functionality as the following bookmark:
javascript:(function(){if(!window.page2rss_bookmark_urlr)window.page2rss_bookmark_urlr=function(ur){if(ur.error)alert(ur.error);if(ur.page&&ur.page.page)location.href=ur.page.page};var r=document.getElementById('urlFormRequest');if(r)r.parentNode.removeChild(r);r=document.createElement('script');r.id='urlFormRequest';r.type='text/javascript';r.src='http://page2rss.com/api/page?url='+encodeURIComponent(location.href)+'&callback=page2rss_bookmark_urlr';document.body.appendChild(r);})();
However, I struggle to correctly translate the javascript code of the bookmark into the logic of a Chrome extension. I thought the best to is to to put the exact code of the bookmark into a separate script create_feed_url.js and execute it in background.js. My background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
// Run the bookmark code
chrome.tabs.executeScript(null, {file: "create_feed_url.js"});
// Open a new tab for a valid url resulting from create_feed_url.js
var feed_url = "http://page2rss.com/page?url=" + tab.url;
chrome.tabs.create({"url": feed_url});
Yet the code in create_feed_url.js somewhat runs not sucessfully. There is no feed URL generated, resulting in a non existing value for feed_url.
My questions:
Could you please help me to find out why I cannot just put the code of the bookmark into create_feed_url.js and run it?
Is this approach of executeScript recommendable in my case or is there a better way translating a bookmark into an extension?
I solved it with a workaround calling the URL that generates the new feed in a new tab before closing it and finally jumping to the tab with the final RSS feed URL. This solution does not require create_feed_url.js but relies completely on background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
// Original bookmark JS code
//(function(){if(!window.page2rss_bookmark_urlr)window.page2rss_bookmark_urlr=function(ur){if(ur.error)alert(ur.error);if(ur.page&&ur.page.page)location.href=ur.page.page};var r=document.getElementById('urlFormRequest');if(r)r.parentNode.removeChild(r);r=document.createElement('script');r.id='urlFormRequest';r.type='text/javascript';r.src='http://page2rss.com/api/page?url='+encodeURIComponent(location.href)+'&callback=page2rss_bookmark_urlr';document.body.appendChild(r);})();
var create_feed_url = "http://page2rss.com/api/page?url=" + encodeURIComponent(tab.url); //+ "&callback=page2rss_bookmark_urlr"
var feed_url = "http://page2rss.com/page?url=" + tab.url;
chrome.tabs.create({"url": create_feed_url, active: false}, function(tab) {
chrome.browserAction.setBadgeText({text: 'wait'});
setTimeout(function() {
chrome.tabs.remove(tab.id, function(tab) {
chrome.browserAction.setBadgeText({text: ''});
});
}, 5000);
});
setTimeout(function() {
chrome.tabs.create({"url": feed_url, active: true}, function(tab) {
chrome.tabs.onUpdated.addListener(function( tabId , info ) {
if ( info.status == "complete" ) {
chrome.browserAction.setBadgeText({text: 'done', tabId: tabId});
}
});
}); }
, 1000);
});
Based on Rob's comment above of using a content script approach I tried to implement it. However, clicking on the browser icon does not trigger the content script create_feed_url.js through content_script.js. I tried to debug the code but neither the Developer Tools nor the inspect element tool show any error.
background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "content_script.js"});
});
content_script.js:
var s = document.createElement('script');
s.src = chrome.extension.getURL("create_feed_url.js");
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
create_feed_url.js:
(function(){if(!window.page2rss_bookmark_urlr)window.page2rss_bookmark_urlr=function(ur){if(ur.error)alert(ur.error);if(ur.page&&ur.page.page)location.href=ur.page.page};var r=document.getElementById('urlFormRequest');if(r)r.parentNode.removeChild(r);r=document.createElement('script');r.id='urlFormRequest';r.type='text/javascript';r.src='//page2rss.com/api/page?url='+encodeURIComponent(location.href)+'&callback=page2rss_bookmark_urlr';document.body.appendChild(r);})();
manifest.json:
{
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"background" : {
"scripts": ["background.js"],
"persistent": false
},
"web_accessible_resources": ["create_feed_url.js"],
"browser_action" :
{
"default_icon" : "rss-19.png",
"default_title" : "Create RSS feed for this page"
},
"manifest_version": 2
}

Resources