I am accessing local storage with JS and displaying the values in the HTML but when DOMPDF renders the page to PDF the values are not displayed in the HTML/PDF (tags are empty).
Error in console:
ReferenceError: localStorage is not defined
My JS code:
window.addEventListener('load', function (ev) {
var UserScoreResults = JSON.parse(localStorage.getItem("score"));
if (UserScoreResults === null) {
window.location.replace('/results/no-results.html');
} else {
var score = UserScoreResults.reduce((a, b) => a + b, 0);
var count = 0;`
for (let i = 0; i < UserScoreResults.length; i++) {`
if (UserScoreResults[i] == 1) {`
if(count == 0) {`
document.getElementById("answer-1").innerHTML = '<button id="q1" type="button" class="btn answer-btn m-0">STRONGLY DISAGREE</button>';
}
etc...
When viewing the PDF page in the browser and looking at the Local storage via dev tools, the values are not there even though it is still on the same site. Original page = [example.com/reference-page/] and PDF page (after render) = [example.com/reference-page/pdf].
I don't know if this is due to the render process of DOMPDF.
Is there a reason for the local storage disappearing that I am missing or am I trying to use a method that does not work with DOMPDF?
Related
I know how to include CSS or JS files using app script in a web script. but that way includes files content on page lode.
My question is it possible to include partial html page inside the currently opened page?
app script to include CSS or JS
/* #Include JavaScript & CSS & HTML-Partial-Views */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
and I use like this
<?!= include('Css'); ?>
and here is my attempt.
html
<button onclick="getList("users")">show some html content</button>
<div id="users"></div>
<script>
function getList(users){
var listUsers = google.script.run.showHtml(users);
// how to return showHtml result [list of users]
for (var i; i <= listUsers.length; 1++)
{
document.querySelector("#users").innerHTML += <div>listUsers[i]</div>;
}
}
</script>
gs
function users(sheetName, pageName){
// get users from sheet
var ss= SpreadsheetApp.openById("435yh35h45b35nh6hg5bwh455j");
var dataSheet = ss.getSheetByName(sheetName);
var dataRange = dataSheet.getDataRange().getValues();
return dataRange;
}
From one of the code snippets
// how to return showHtml result [list of users]
Try this:
<button onclick="getList('users')">show some html content</button>
<div id="users"></div>
<script>
function getList(users){
var listUsers = google.script.run
.withSuccessHandler((listUsers) => {
let list = '';
for (var i; i < listUsers.length; i++) {
list += `<div>${listUsers[i]}</div>\n`;
}
document.querySelector("#users").innerHTML = list;
})
.showHtml(users);
}
</script>
Changes done
Replaced "users" by 'users'
Added withSuccessHandler with an arrow function as callback.
The arrow function build a string using a for statement (because it was used in the original code) including a div tag using a template literal.
I am trying to create an IE11 compatible webpage which will sit on a few users desktops, which will grab some data from a JSON API and display it.
The user will type in their individual API key before pressing a button, revealing the API data.
Could you please help where my code has gone wrong? The error message I get from the console is: "Unable to get property 'addEventListener' of undefined or null reference. " So it looks like it is not even making the call to the API.
<script>
var btn = document.getElementById("btn");
var apikey = document.getElementById("apikey").value
btn.addEventListener("click", function() {
var ourRequest = new XMLHttpRequest();
ourRequest.open('GET', 'http://example.example?&apikey=' + document.getElementById("apikey").value);
ourRequest.onload = function() {
if (ourRequest.status >= 200 && ourRequest.status < 400) {
var ourData = JSON.parse(ourRequest.responseText);
document.getElementById("title").textContent = ourData.data[0]["name"];
}}}
);
</script>
.
<body>
Enter API key: <input type="text" id="apikey">
<button id="btn">Click me</button>
<p id="title"></p>
</body>
The API data which I am trying to just extract the name from, looks something like this:
{"data":[{"name":"This is the first name"},{"name":"This is the second name"}]}
It's likely that you're including the Javascript in the page before the HTML. As Javascript is executed as soon as the browser reaches it, it will be looking for the #btn element which will not have been rendered yet. There are two ways to fix this:
Move the Javascript to the bottom of the <body> tag, making it run after the HTML has been output to the page.
Wrap the Javascript in a DOMContentLoaded event, which will defer the script until the page has finished loading. An example is as follows:
window.addEventListener('DOMContentLoaded', function() {
var btn = document.getElementById('btn');
var apikey = document.getElementById("apikey").value;
[...]
});
I'm trying to make use of the New Google Sites for a web page that I've developed, however, I'm having trouble storing local data. Local files work fine in windows and apple safari/chrome. Try it from Google Sites, and no joy! Additionally, in safari, an error is thrown, "IDBFactory.open() called in an invalid security context".
I really would like to host my site via google sites without linking to another server. I specifically need locally persistent data for just a few small items. I can't seem to make cookies work either.
Any suggestions?
I have tried this on a Windows 10 Surface Pro 2017, Apple iPad running 12.2 of Safari, Apple Mac Mini running macOs Mojave 10.14. I use SimpleHTTPServer from Windows 10 command line to share the files as a web server. I also email the files and open directly on the specified systems. Finally, I have created a New Google Sites website at https://sites.google.com/view/gerrymap It's very simple, just an Embed HTML element with the below text copied into the source code edit box. All are welcome to hit that page if they desire. Otherwise, use the short posted file below.
Instructions are in the HTML page itself.
All code works fine from a local instance of the html file. Can enter new values for the lat, long, rad, and key, save them, and read them. I can also refresh the page, then read them without storing first, and there is no problem. This proves that the values aren't just session persistent.
From Google Sites is a different matter. I set up a site that uses the html file in this question. When I enter new values and press the save button, IndexedDB fails, but localStorage succeeds in returning the values saved. If I press the refresh button, however, and then read the values without attempting to store first, IndexedDB again fails, but localStorage also fails in that it doesn't retrieve any values.
I believe I've correctly implemented the code (although some out there may take exception, I'm sure. No pride here, critics are welcome).
I've done a bunch of google searches, particularly about google sites and indexeddb/localstorage, and also posted on the google community help forum. Still no success.
Currently, I have no fallback methods, but need something relatively simple. Can anyone throw a little joy my way? Thanks in advance!
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Test Local Storage</title>
<style>
</style>
</head>
<body onload="initializeValues()">
Instructions: <br />
1. Save this sample code in an html file locally and open in a browser.<br />
2. Enter different values into the lat, long, rad, and key edit boxes.<br />
3. Press TrySave to store the values in indexedDB and localStorage.<br />
4. Refresh the webpage from the browser address line<br />
5. Press the individual Try IndexedDB and Try LocalStorage buttons to attempt<br />
6. Try inserting this code into a New Google Site, or access https://sites.google.com/view/gerrymap/home <br />
<br>
<input id="latitude" /> Latitude<br><br>
<input id="longitude" /> Longitude<br><br>
<input id="radius" /> Radius<br><br>
<input id="key" /> Key<br><br>
<button onclick="TryIndexedDB()" title="This tries to load via IndexedDB">Try IndexedDB</button><br><br>
<button onclick="TryLocalStorage()" title="This tries to load via localStorage">Try localStorage</button><br><br>
<button onclick="trySave()" title="This tries to save the data in both methods (IndexedDB, localStorage)">Try Save</button><br><br>
<button onclick="clearAll()" title="Clear the log space at the bottom of this example page">Clear Log</button><br><br>
<div id="hello">
</div>
<script>
"use strict";
function clearAll() {
document.getElementById("hello").innerHTML = "";
}
// tagBeginDefaultsReplace
var navLatitude = 39;
var navLongitude = -76.7;
var navMaxDist = 200;
var navKey = "PleaseAddYourKey";
function initializeValues() {
document.getElementById("latitude").value = navLatitude;
document.getElementById("longitude").value = navLongitude;
document.getElementById("radius").value = navMaxDist;
document.getElementById("key").value = navKey;
}
function trySave() {
navLatitude = document.getElementById("latitude").value;
navLongitude = document.getElementById("longitude").value;
navMaxDist = document.getElementById("radius").value;
navKey = document.getElementById("key").value;
// Save using indexeddb
getLocationDB(true, FinishIndexedDB);
// Save using localStorage
localStorage.setItem('latitude', navLatitude.toString());
localStorage.setItem('longitude', navLongitude.toString());
localStorage.setItem('radius', navMaxDist.toString());
localStorage.setItem('key', navKey.toString());
mylog("Done saving localStorage");
}
function getLocationDB(bSave, callbackf) {
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
var openDB;
try {
var myitem;
openDB = indexedDB.open("SampleDatabase", 1);
openDB.onupgradeneeded = function () {
var db = openDB.result;
var store = db.createObjectStore("SampleStore", { keyPath: "id" });
var index = store.createIndex("PosIndex", ["pos.latitude", "pos.longitude", "pos.radius", "pos.navkey"]);
};
openDB.onsuccess = function () {
// Start a new transaction var db = openDB.result;
callbackf("Successfully opened openDB");
var db = openDB.result;
var tx = db.transaction("SampleStore", "readwrite");
var store = tx.objectStore("SampleStore");
if (bSave) {
if (navLatitude != undefined && navLongitude != undefined && navMaxDist != undefined)
store.put({ id: 0, pos: { latitude: navLatitude, longitude: navLongitude, radius: navMaxDist, navkey: navKey } });
else
store.put({ id: 0, pos: { latitude: "38", longitude: "-75.7", radius: "100", navkey: "Please Enter Mapbox Key" } });
callbackf("Save indexeddb finished");
}
else {
var getNavLoc = store.get(0);
getNavLoc.onsuccess = function () {
if (getNavLoc != undefined
&& getNavLoc.result != undefined) {
callbackf("Succeeded reading from store. Result=" + JSON.stringify(getNavLoc.result));
navLatitude = parseFloat(getNavLoc.result.pos.latitude);
navLongitude = parseFloat(getNavLoc.result.pos.longitude);
navMaxDist = parseFloat(getNavLoc.result.pos.radius);
navKey = getNavLoc.result.pos.navkey;
}
else {
callbackf("Succeeded reading from store. Result=undefined");
navLatitude = navLongitude = navMaxDist = navKey = "undef";
}
initializeValues();
}
getNavLoc.onerror = function () {
callbackf("An error occurred getting indexeddb");
}
}
}
openDB.onerror = function () {
callbackf("An error occurred opening openDB");
}
}
catch (e) {
callbackf("Caught error in try block of indexeddb: " + e.Message);
}
}
function TryIndexedDB() {
getLocationDB(false, FinishIndexedDB);
}
function TryLocalStorage() {
mylog("localStorage read");
navLatitude = localStorage.getItem('latitude');
mylog("latitude=" + navLatitude);
navLongitude = localStorage.getItem('longitude');
mylog("longitude=" + navLongitude);
navMaxDist = localStorage.getItem('radius');
mylog("radius=" + navMaxDist);
navKey = localStorage.getItem('key');
mylog("key=" + navKey);
if (navLatitude == undefined)
navLatitude = "undef";
if (navLongitude == undefined)
navLongitude = "undef";
if (navMaxDist == undefined)
navMaxDist = "undef";
if (navKey == undefined)
navKey = "undef";
initializeValues();
}
function FinishIndexedDB(nSucceeded) {
mylog(nSucceeded);
}
function mylog(logstr) {
document.getElementById("hello").innerHTML += "<br>" + logstr.toString();
}
</script>
</body>
</html >
The problem is the way Google Sites is serving the iframe content. I'm not sure of the exact details behind the scenes, but it seems to have a randomly generated domain every time the page loads. Since localStorage and IndexedDB are associated with a specific domain, this causes the saved data to be "lost" when the page reloads.
As an example, here is the iframe's data from when I first loaded the page:
And here is the iframe's data after refreshing the page:
As you can see, the domain is completely different after refreshing, which means it has a brand new empty database.
what I' trying to accomplish is a Google Spreadsheet for a project management. I've got lots of cells in a grid where a user should select either the item was completed or not. Now this spreadsheet would be available only to a Project Manager. The way I imagined the process would work was that Project Manager selects particular cells and assigns them to a technician's email address. Script would then generate mobile friendly html UI and send it to the technician (I thought of Google forms but I want to create more customized UI). Technician would then select a checkbox after completing a task which would at the same time update the spreadsheet. Next time technician would open the UI it would populate all the checkboxes that previously were selected.
The only way I've found that I could make it work was a google script web app bounded to a spreadsheet. I've created a test HTML file and .gs file:
.html file
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<h1> Web App Test </h1>
<input type="button" value="Click Me" id="buttonclicked" onclick="getSomeData()"/>
<div id="output" class="current">output</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
function getSomeData()
{
google.script.run
.withSuccessHandler(onSuccess)
.withFailureHandler(showError)
.testForWebApp();
myLog("in WebAppTest.html getSomeData()");
}
function onSuccess(testParam)
{
var div = document.getElementById('output');
if (sectionName == null)
div.innerHTML = "<p style='color:red;'>You didn't hit the script</p>";
else
div.innerHTML = "<p style='color:white;'>" + testParam + "</p>";
}
function showError()
{
var div = document.getElementById('output');
div.innerHTML = "<p style='color:red;'>You didn't hit the script</p>";
}
</script>
</body>
and .gs file:
function doGet()
{
return HtmlService.createHtmlOutputFromFile('WebAppTest')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function testForWebApp()
{
myLog("In testForWebApp()");
var msg = "Yep you hit the script!";
return msg;
}
function myLog(log)
{
//log = 'test';
Logger.log(log);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('log');
var lastRow = sheet.getLastRow();
sheet.insertRowBefore(1);
var newLogDateRange = sheet.getRange(1, 1);
var newLogTextRange = sheet.getRange(1, 2);
var now = new Date();
newLogDateRange.setValue(now);
newLogTextRange.setValue(log)
}
When I published the app and followed the generated link I saw my html page with a Click Me button. The click event ran the getSomeData() function which called google.script.run function. The server side .testForWebApp() gotten executed because I've gotten a log entry from myLog() but the .withSuccessHandler or .withFailureHandler were never called. At the same time the myLog() that should be executed after google.script.run never run either.
I definitely don't understand how it works and suspect that if I publish a script as a web app the HTML is not bounded to the script anymore, but I couldn't find any information about it online.
Thanks for your help.
Firstly, you cannot call server-side myLog() function from your client side javascript unless you call it using google.script.run.myLog() Therefore
myLog("in WebAppTest.html getSomeData()");
in your getSomeData() doesnt log anything in your google sheet
Secondly, this code in function onSuccess(testParam)
if (sectionName == null)
is causing your function to terminate prematurely, since there is no variable called sectionName defined.
Note: You can monitor all these errors in the console of your web browser.
Below is the modified code that should work as you intend it to
Final code:
Web App Test
output
function getSomeData()
{
google.script.run
.withSuccessHandler(onSuccess)
.withFailureHandler(showError)
.testForWebApp();
console.log("in WebAppTest.html getSomeData()"); //Log it on the browser console
}
function onSuccess(testParam)
{
var div = document.getElementById('output');
if (testParam == null) // Changed it to testParam from sectionName, to check the value returned from testWebApp()
div.innerHTML = "<p style='color:red;'>You didn't hit the script</p>";
else
div.innerHTML = "<p style='color:black;'>Success:" + testParam + "</p>";
}
function showError()
{
var div = document.getElementById('output');
div.innerHTML = "<p style='color:red;'>You didn't hit the script</p>";
}
Edit
One last note, the below code would make the return text invisible as the text and background color would be the same color (white):
div.innerHTML = "<p style='color:white;'>Success:" + testParam + "</p>";
hence changed the text color to black in the final code
Hope that helps!
Try redeploying the web app, but under a new project version.
I'm trying to figure out the flow of using google's scripts to copy images from a user's hard drive to a public folder on their Google Drive. (see https://developers.google.com/apps-script/reference/utilities/utilities#unzip%28BlobSource%29 ) Question is, do I have to write a google script that I publish as a web app from script.google.com, or can I have the script inside the javascript on the client's browser? Google has a sample of uploading images one at a time: "developers.google.com/drive/web/quickstart/quickstart-js"
I would like to upload one zipped file of images, unzip them and then reduce the size before they are stored in the user's Google Drive.
Here is some code that unzips files, but it looks like they are running this from script.google.com; it does not work: (http://webcache.googleusercontent.com/search?q=cache:NsTvlj17H4MJ:ctrlq.org/code/19506-google-drive-hosting&client=firefox-a&hs=ZEF&hl=en&gl=us&strip=1)
This is a script that I modified for another user that allows for multiple files (validation could probably limit file types to images) to be uploaded from the user's hard drive to a specific folder. The folder would be set to share publicly. You would simply change the folderID string to the string that matches the folder where you wanted to files to arrive. Put this script in a Google Sites page, and change the id in the doPost(e) function, and it should do what you want it to do. I'm not sure about the zipping and unzipping. You would publish the script in a google site as a public webapp widget.
You can see the UiApp interface here, but if you try to upload something, you will get an error because I've removed the folderId link to my drive since I put this answer live. If you need more explanation about how or why it works, let me know. Use the + and - buttons to add more files to the upload, or remove a file that you don't want to include. The files can be zips or any file type, but there isn't code included to unzip anything after it's uploaded.
//modified from script found here http://www.googleappsscript.org/miscellaneous/creating-form-elements-dynamically-using-google-apps-script-gas
//additional help from Serge to fix an error in my original code.
function doGet() {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
var formPanel = app.createFormPanel();
var instructionsLabel = app.createLabel('Put your instructions here');
var filesLabel = app.createLabel('Add Files to Upload');
var table = app.createFlexTable().setId('table').setTag('0'); //Here tag will count the number of files
//Write the header for the table
var header = app.createLabel('File(s)');
table.setWidget(0, 0, header);
//Add the first row of files
addFirstRow(app);
var hidden = app.createHidden().setId('hiddenRowHolder').setName('hidden').setValue(table.getTag());
//Add a button to submit the info
var button = app.createSubmitButton('Upload File(s)');
panel.add(instructionsLabel).add(filesLabel).add(table).add(hidden).add(button);
formPanel.add(panel);
app.add(formPanel);
return app;
}
function addFirstRow(app){
var table = app.getElementById('table');
var tag = parseInt(table.getTag());
Logger.log(tag);
var numRows = tag+1;
if(numRows >1){
table.removeCell(numRows-1, 5);
table.removeCell(numRows-1, 4);
}
Logger.log(numRows);
var uploadWidget = app.createFileUpload();
table.setWidget(numRows, 0, uploadWidget);
table.setTag(numRows.toString());
addButtons(app);
}
function addButtons(app){
var table = app.getElementById('table');
var numRows = parseInt(table.getTag());
//Create handler to add/remove row
var addRemoveRowHandler = app.createServerHandler('addRemoveRow');
addRemoveRowHandler.addCallbackElement(table);
//Add row button and handler
var addRowBtn = app.createButton('+').setId('addOne').setTitle('Add row');
table.setWidget(numRows, 4, addRowBtn);
addRowBtn.addMouseUpHandler(addRemoveRowHandler);
//remove row button and handler
var removeRowBtn = app.createButton('-').setId('removeOne').setTitle('Remove row');
table.setWidget(numRows, 5, removeRowBtn);
removeRowBtn.addMouseUpHandler(addRemoveRowHandler);
}
function addRemoveRow(e){
Logger.log(e.parameter.source);
var app = UiApp.getActiveApplication();
var table = app.getElementById('table');
var tag = parseInt(e.parameter.table_tag);
var hidden = app.getElementById('hiddenRowHolder');
var source = e.parameter.source;
//Logger.log(tag);
if(source == 'addOne'){
table.setTag(tag.toString());
hidden.setValue(tag+1);
addFirstRow(app);
}
else if(source == 'removeOne'){
if(tag > 1){
//Dcrement the tag by one
var numRows = tag-1;
table.removeRow(tag);
//Set the new tag of the table
table.setTag(numRows);
hidden.setValue(numRows);
//Add buttons in previous row
addButtons(app);
}
}
return app;
}
function doPost(e) {
var numFiles = Number(e.parameter.hidden);
Logger.log(numFiles);
for (var i = 1; i<=numFiles; i++){
var fileBlob = e.parameter['file'+i];
var newFile = DocsList.getFolderById("YOUR FILE FOLDER ID").createFile(fileBlob);//replace string with folder id where you want to place your files
}
var app = UiApp.getActiveApplication();
var label = app.createLabel(numFiles +' file(s) uploaded successfully');
app.add(label);
return app;
}