createHtmlOutput() not work in GAS - google-apps-script

I wrote a Script in about 1yr before.
Today when I run it again, the command HtmlService.createHtmlOutput(HTMLToOutput) seems not longer work, with this error shown on my Chrome (which hasn't disallowed Javascript):
"The current browser does not support this feature. Please upgrade to a newer browser."
My code is standard code inside doGet(e). Even this simplified version won't work also:
function doGet(e) {
...
HTMLToOutput = "<html><h1>Install this App into your Google Drive!</h1><a href='" + getURLForAuthorization() + "'>click here to start</a></html>";
return HtmlService.createHtmlOutput(HTMLToOutput).setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function getURLForAuthorization() {
return AUTHORIZE_URL + '?response_type=code&client_id=' + CLIENT_ID + '&redirect_uri=' + REDIRECT_URL + '&scope=' + AUTH_SCOPE;
}
Do anyone know the reason?

I had the same issue. I was able to solve it by adding this
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
so, total line should look like this:
HtmlService.createHtmlOutput(HTMLToOutput).setSandboxMode(HtmlService.SandboxMode.IFRAME);

Related

Can't serve HTML on the Google Apps Script callback page in a GMail add-on

I am working on a GMail add-on that connects to a third-party service through OAuth2. To obtain the authorization code the following redirect URI is used: https://script.google.com/macros/d/[SCRIPT_ID]/usercallback .
Here's a snippet that triggers authorization:
var stateToken = ScriptApp.newStateToken()
.withMethod( "authCallback" )
.withTimeout( 120 )
.createToken();
var authUrl = _authBaseUrl
+ "&client_id=" + encodeURIComponent( _clientId )
+ "&redirect_uri=" + encodeURIComponent( _redirectUri )
+ "&state=" + stateToken;
CardService.newAuthorizationException()
.setAuthorizationUrl( authUrl )
.setResourceDisplayName( "Resource" )
.throwException();
And here's the callback function (the HTML snippet is taken from here):
function authCallback( request )
{
createAccessToken( request.parameter.code );
return HtmlService.createHtmlOutput('Success! <script>setTimeout(function() { top.window.close() }, 1);</script>');
}
The createAccessToken function gets successfully invoked and the add-on gets an access token. However, the HTML is not served in the popover window. Instead, there's a placeholder with the following error: "The script completed but did not return anything."
As a result, I am stuck with an error window which can't be closed automatically and doesn't tell user that they have to close the window to continue working with the add-on.
Is there anything wrong I am doing or this is some kind of bug or a dropped feature? Thanks for any suggestions.
UPD:
The error looks like this
Turns out the HtmlService actually works in that case. I had a function name collision for authCallback, so the proper one wasn't invoked. Sorry for misinformation. If anyone has trouble handling the callback window, do as described in the question.

Extract used CSS from a page

I need to extract the used CSS from a 19,000 line CSS file where 98.4% of it is unused (ouch). I know you can use Chrome Developer Tools to view the CSS Coverage, like so:
But it doesn't allow you to even jump to the green lines. Manually going through 19K lines just doesn't seem feasible.
Chrome Lighthouse doesn't seem to give you an option to see only the rules you need like Developer Tools used to, either.
I've tried Firefox's "CSS Usage" add-on (which a lot of sites recommend) but it requires FireBug, which itself isn't compatible in the current version of FireFox.
Can anyone think of a way to pull out just the CSS that's used somehow?
Hope this will help you
https://uncss-online.com/
just add html in left and css in right. Click ok btn then see magic
if there is any error in css then it will ask you to remove that error in that line number.
This is the easiest methode :)
After downloading the Coverage .json from Chrome (>= v73) [What's New In DevTools - Chrome 73].
You can extract the CSS with this node script:
$ node extractCSS.js ~/Desktop/Coverage-20190325T110812.json
https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
https://d33wubrfki0l68.cloudfront.net/css/1bd6a34e1fcf409d29d1a960e6299893fca2e7b1/css/all.css
https://unpkg.com/bootstrap#4.1.3/dist/css/bootstrap.min.css
./final_css.css file saved
// extractCSS.js
const fs = require('fs');
let final_css_bytes = '';
let total_bytes = 0;
let used_bytes = 0;
const filename = process.argv[2];
const output = './final_css.css';
if (!filename) {
console.error('Missing filename to get coverage information from');
process.exit();
}
const file_coverage = fs.readFileSync(filename);
const css_coverage = JSON.parse(file_coverage);
for (const entry of css_coverage) {
if (!entry.url.endsWith('.css')) continue;
console.log(entry.url);
final_css_bytes += '# ' + entry.url + '\n\n';
total_bytes += entry.text.length;
for (const range of entry.ranges) {
used_bytes += range.end - range.start - 1;
final_css_bytes += entry.text.slice(range.start, range.end) + '\n';
}
final_css_bytes += '\n\n';
}
fs.writeFile(output, final_css_bytes, error => {
if (error) {
console.log('Error creating file:', error);
return;
}
console.log(output, 'file saved');
});
https://gist.github.com/gianpaj/a2f99e022e2c3f8abb9deecb47d572c4
Inspired by: https://blog.fullstacktraining.com/remove-unused-css-javascript-code-from-your-project/
I use PurifyCSS for some of my projects. Helps me to keep my CSS lightweight.
Dont' know about your project structure and workflow, but there are tons of tutorials out there:
https://webdesign.tutsplus.com/tutorials/remove-unnecessary-css-with-purifycss-and-grunt--cms-27726
https://survivejs.com/webpack/styling/eliminating-unused-css/
There are also some online solutions for getting rid of unused CSS, never tried though:
https://uncss-online.com/

xmlhttprequest always returning status 0 even client and server on same machine

i know this questions asked several times, and i am referring all these post, even after that also not able to solve my problem. I have created a html page for client server communication. Here is the code
<!DOCTYPE html>
<html>
<head>
<title>Sandbox</title>
<script type="text/javascript">
function log (text) {
document.getElementById("contents").innerHTML = document.getElementById("contents").innerHTML + "<br />" + text;
}
function ready() {
log("Ready.");
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
log("State: " + xmlhttp.readyState + ", Status: " + xmlhttp.status
+ ", Statustext: " + xmlhttp.responseText);
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
log("CSV Content:");
log(xmlhttp.responseText);
}
};
log("Open.");
xmlhttp.open("GET", "http://10.5.13.142/iptvservice.xml", false);
log("Send.");
xmlhttp.send(null);
log("Sent.");
window.removeEventListener('DOMContentLoaded', ready, false);
}
window.addEventListener('DOMContentLoaded', ready, false);
</script>
</head>
<body>
<div id="contents">Loading.</div>
</body>
</html>
server is a Apache server.I am running this page on a same machine where server installed. On Mozilla status code is 0 and on It hanged on loading. I am not getting what is the problem. i have read that you don't need to set the permission on manifest.json if you are on the same domain. Then where i am getting wrong. Please help.
Edit: Actually my requirement is to run this code on android using phonegap. So i want to do using java script. So anybody can suggest using xmlhttprequest how to create client server connection.
sorry, but just now i got this link
XMLHttpRequest Fails On Same Domain
but in my case Apache server giving xml page. So where i should put my script.and this is just for testing purpose i am using same machine, but after that i need to run same page on different machine. Then what would be the solution. sorry i am asking very simple question, but required little help.
Edit: just for information. I did change according to the link
http://www.skill-guru.com/blog/2011/02/04/adding-access-control-allow-origin-to-server-for-cross-domain-scripting/
and then ran on google chrome, it worked, but it still not working on firefox. Anyways, atleast my code and server installation is proper.

Geolocation not working with HtmlService

I created the following two files:
code.gs
function doGet() {
var html = HtmlService.createHtmlOutputFromFile('html.html');
return html;
}
html.html
<html>
<body>
<p id="messaging">Click the button to get your coordinates:</p>
<button onclick="getLocation()">Where am I</button>
<script>
var message=document.getElementById("messaging");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
message.innerHTML="Geolocation is not supported.";
}
}
function showPosition(position) {
message.innerHTML="Latitude: " + position.coords.latitude + "<br>Longitude: " + position.coords.longitude;
}
</script>
</body>
</html>
When I call the published URL, I get the expected message and button. Click the button and I get my failure message "Geolocation is not supported". If I save html.html in a file and open it in a browser it works as expected.
Any ideas?
As of 2016, geolocation works with HtmlService in IFRAME mode. Test it here: GAS-geolocation
Tested with Chrome and Firefox (desktop), both ok. Doesn't work with Safari (desktop) (the share location confirmation box doesn't popup. I hate Safari!)
Funny thing is, it works with Safari on iOS 9 but not the latest Chrome on iOS 9. (same issue, no confirmation popup)
GeoLocation is not yet available in HtmlService
I believe, Caja is culprit here. Could you run your code on Caja playground to check if the behavior is same. If same, you may open an issue in Caja Issue Tracker
To know more what Caja does with HtmlService, you may refer to this page.
Update
Above answer is obsolete. Now one can access location using navigator.geolocation object available in browser.
I just tried your code, as I'd like to do something with Google Apps Script in Google Sites.
It appears that GeoLocation is still not supported in HTMLService at this time, but I found a possible workaround for my specific need (i.e. in conjunction with Google Sites) that may help someone else too :
What does work, is to create a custom "Google Sites Gadget"
using the example code from tutorials point
I end up with a 'skeleton' XML file for my gadget as such :
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="GeoLocation"
>
</ModulePrefs>
<Content type="html"><![CDATA[
<form>
<input type="button" onclick="getLocation();"
value="Get Location"/>
</form>
<script>
function showLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
alert("Latitude : " + latitude + " Longitude: " + longitude);
}
function errorHandler(err) {
if(err.code == 1) {
alert("Error: Access is denied!");
}else if( err.code == 2) {
alert("Error: Position is unavailable!");
}
}
function getLocation(){
if(navigator.geolocation){
// timeout at 60000 milliseconds (60 seconds)
var options = {timeout:60000};
navigator.geolocation.getCurrentPosition(showLocation,
errorHandler,
options);
}else{
alert("Sorry, browser does not support geolocation!");
}
}
</script>
]]></Content>
</Module>
Now instead of the alerts, I can pass the results to the Google Apps Scripts Web App as a URL parameter.
It's not ideal, but seems to work ok so far.

Webworker is not running

I have the following code:
var stressWorker = new Worker("./test/webworkers/worker.js");
stressWorker.onmessage = function(event){
alert(event.data);
};
stressWorker.onerror = function(event){
throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
};
worker.js:
onmessage = function(e){
postMessage("test");
}
The script finds the 'worker.js' file but it doesn't actually run it. What am I doing wrong?
PS. I'm hosting both scripts using wamp and I'm using chrome
worker.js won't do anything until it receives a message. I can't see where you are sending it a message. You need something like stressWorker.postMessage(...) somewhere.
Are you sure your browser supports this particular HTML5 feature?
This article has many ways to test for support of each feature. The test for Worker is
return !!window.Worker;
Edit: As I see it, there's either a problem with your code or it can't find the file. Your code looks a lot like this example except there the .js file code is like this, with the self:
self.onmessage = function(e) {
self.postMessage("Hello " + e.data);
};
It should be easy enough for you to try that and see if it's the missing piece here.
One main thing You should remember If you are running scripts on same origin and using chrome, you should start the chrome with the flag --allow-file-access-from-files or You should run app on local server.
See the code
var stressWorker = new Worker("../test/webworkers/worker.js");
stressWorker.onmessage = function(event){
alert(event.data);
};
stressWorker.postMessage("Hello there");
stressWorker.onerror = function(event){
throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
};
Now you will get The response from the worker. ".." I suspect path is wrong.