This is continuation of question asked here (Provide link to iframe via js) as a second part. Here I am opening my iframe link. The iframe link opens up a PDF. I am currently running the code in localhost server which is why the address is http://127.0.0.1:5500. But when I upload it to the main server, this will be changed. My question is, since the link of the PDF is stored in the same directory as the index.html page. How do I automatically generate http://127.0.0.1:5500 or any other address depending on the hosting server. Such that it could be www.myhostingserver.come/myID/PDFIni.pdf and I do not have to manually enter the hosting address, rather just give : hostingaddress+"/PDFIni.pdf"?
<script>
...
...
let myIframe = document.getElementById("iframe");
if(myIframe.src != "http://127.0.0.1:5500/PDFIni.pdf")
{
console.log(myIframe.src);
myIframe.src = "http://127.0.0.1:5500/PDFIni.pdf";
}
Try to use document.location.hostname. For example:
var str = 'https://' + document.location.hostname + '/PDFIni.pdf';
if(myIframe.src != str) {
console.log(myIframe.src);
myIframe.src = str;
}
Related
I am currently using Nodejs to have post multiple html files I have
app.get('/',function (req,res) {
//console.log(Date().toString() +'\n' + "Client side Viewing.........\n");
res.sendFile('C:\\Users\\Documents\\Document\\F10N_MFG\\Commit\\Commit.html');
});
app.get('/Commit_Edit',function (req,res) {
//console.log(Date().toString() +'\n' + "Client side Viewing.........\n");
res.sendFile('C:\\Users\\Documents\\Document\\F10N_MFG\\Commit\\Commit - Edit.html');
});
and I use SocketIo to pass variable around from client to server and server back to client
I want to have a page that collect a client selection (variable) and pass back to server and the server will trigger that client-side to open a new browser tab that bring over the variable he choose only to that specific client
and meanwhile not changing other clients selection.
is it possible?
for now,
I have an solution by including the variables in link address
I added the variable in the link and run it
http://mfgrpa2:4000/lot_list?param=value/
var x = window.location.href.search("param=");
var y = window.location.href.substring(x+6,window.location.href.length);
var z = y.replaceAll("%20"," "); //replace any %20 to space;
console.log(z);
and it works.
I can restrict the usage of the Web App but I cannot limit the access to the images referred in the <img> tag.
Now I am developing a Web application with Google Apps Script.
This is an internal application of the corporation and I got to set the assets' access rights carefully.
For App itself, from Deploy as web app box of the script editor, I set Execute the app as Me (bar#foo.example.com) and Who has access to the app as Anyone within FOO corporation.
(Here let's say I belong to the FOO corporation. My Google account is bar#foo.example.com)
Now, when I login with the Google account of FOO, I could successfully access the Web App.
But when I didn't login, I couldn't access it.
That's what I want.
But when I set <img> tag to show the jpeg file in the Google Drive, I got to set the Share of the image file as Anyone on the internet with this link can view.
When I set <img> tag in the HTML in the Web App project and set the Share of the jpeg file as FOO Corporation -- Anyone in this group with this link can view, the <img> tag will not work (Error 403 will be returned).
I want to restrict the images' access right as well as the web app.
How can I do it?
How to reproduce
put jpeg file
put any JPEG (let's say it is baz.jpeg) file in the Google Drive
right-click and select Share
set the Get link as FOO Corporation -- Anyone in this group with this link can view
double click baz.jpeg to preview it
select ︙ => Open in new window
let's say the URL was https://drive.google.com/file/d/xxxx_object ID_xxxx/view. record the object ID (here xxxx_object ID_xxxx)
create a new untitled script project
create an index.html file and add the code:
<html>
<head>
<base target="_top">
</head>
<body>
<img src="https://drive.google.com/uc?id=xxxx_object ID_xxxx" width="30" height="30" alt="error alt text">
</body>
</html>
create Code.gs
change Code.gs as following code
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
Save it
publish it as Web App
Select menu item Publish > Deploy as web app
In Deploy as web app box, set Project version: as New
Set Execute the app as: as Me (bar#FOO.example.com)
Set Who has access the app: as Anyone within FOO corporation
Click Deploy
Click the text latest code in the message Test web app for your latest code
the result -- error
the webpage index.html is displayed
the image is not displayed. the icon of the broken picture is displayed
the alt text "error alt text" is displayed
if I right-click the icon of the broken picture and select Open in the new tab then it will open Error 403 (Forbidden) tab. The content is as follows:
Google (logo)
403. That’s an error.
We're sorry, but you do not have access to this page. That’s all we know.
change the access right of the image file
In Google Drive, find the image file baz.jpeg
right-click and select Share
set the Get link as Anyone on the internet with this link can view.
Open the tab of the Web App with the broken picture icon and reload
You see the correct image
What I want to do?
I want to set the access right of the image restricted as well as the Web app (only the user of FOO corporation can access).
How can I do it?
403 Forbidden
The /uc endpoint, when the file permission is set to "in this group", returns a 403 Forbidden response even if you are logged in the G Suite account.
Workaround
You can implement a flow of dynamically appending an HTMLImageElement with src attribute set to image data (base-64 encoded string from bytes). With this, you can restrict access to both Web App and the image and still be able to load it.
When deploying the Web App, make sure that the deployment has sufficient access to the file, for example, when the file has "Anyone in this group with this link can view" permissions:
Execute the app as: Me
Who has access to the app: Anyone within [org]
Below is a small proof of concept, including a server-side utility and a sample HTML file.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const asyncGAPIv2 = ({
funcName,
onFailure = console.error,
onSuccess,
params = []
}) => {
return new Promise((res, rej) => {
google.script.run
.withSuccessHandler(data => {
typeof onSuccess === "function" && onSuccess(data);
res(data);
})
.withFailureHandler(error => {
typeof onFailure === "function" && onFailure(error);
rej(error);
})
[funcName].apply(null, params);
});
};
const fetchAndAppendImage = async ({ parent = document.body, id }) => {
const data = await asyncGAPIv2({
funcName: "getImageFromDrive",
params: [{ id, token }]
});
const img = document.createElement("img");
img.src = data;
parent.append(img);
};
(async () => await fetchAndAppendImage({ id: "id here" }))();
</script>
</body>
</html>
You can pass the id to a server-side utility, get the file with getFileById (native authentication flow will ensure the requester will not get access to a file they do not have access to), and form an image data string by doing the following:
Extract raw bytes from the File instance by changing getBlob to getBytes.
Use the base64Encode method of the Utilities service to convert bytes to a base-64 encoded string and prepend data:image/png;base64, (Data URL scheme). If your images have another MIME-type, amend accordingly.
/**
* #summary gets an image from Google Drive
*
* #param {{
* id : string
* }}
*
* #returns {string}
*/
const getImageFromDrive = ({ id }) => {
try {
const file = DriveApp.getFileById(id);
const bytes = file.getBlob().getBytes();
const data = `data:image/png;base64,${Utilities.base64Encode(bytes)}`;
return data;
} catch (error) {
console.warn(error);
return "";
}
};
Notes
For the above to work, you must have the newer V8 runtime enabled.
It is possible that the reason is being logged in into multiple accounts, as trying to access a file via /uc endpoint with "in this group" permission while being only logged in to a G Suite account has no authorization issues.
From Oleg Valter's answer and discussions with him, as a method, I would like to propose to use Templated HTML. The origin of these methods is Oleg Valter's answer. When your script is modified, it becomes as follows.
Google Apps Script side:
From:
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
To:
function doGet() {
const id = "###"; // <--- Please set the file ID of the image file.
const html = HtmlService.createTemplateFromFile('index');
html.image = getImageFromDrive({id: id}); // <--- This function is from Oleg Valter's answer.
return html.evaluate();
}
HTML side:
From:
<img src="https://drive.google.com/uc?id=xxxx_object ID_xxxx" width="30" height="30" alt="error alt text">
To:
<img src="<?!= image ?>" width="30" height="30" alt="error alt text">
Note:
The function of getImageFromDrive by Oleg Valter's answer is used.
When you modified the script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to the Web Apps. Please be careful this.
Reference:
HTML Service: Templated HTML
I'm using the following when trying to open a local file:
some document
When I click the above in a browser, it opens Finder to the folder. But does not open the file. Should I be doing something else to have the file open in Numbers?
You cannot open local files on the client. This would be a huge security risk.
You can link to files on your server (like you did) or you can ask the client for a file using <input type="file">
You can only open some types of files in browsers, like html css js and mp4, otherwise the browser will want to download it. Also remember that browsers replace spaces with %20. I recommend right clicking the file and opening it with chrome then copy that link and using it.
You can open files that are local as long as it is a file that is on the file that is trying to open another file is local.
Your issue is likely the space in the document name. Try this instead:
some document
The %20 will be read by your browser as a space.
Update
The other answer points out something I missed. The .numbers extension will not be able to be opened directly by your browser. Additionally the other answer describes the security risk this could create.
The File API in HTML 5 now allows you to work with local files directly from JS (after basic user interaction in selecting the file(s), for security).
From the Mozilla File API docs:
"The File interface provides information about files and allows JavaScript in a web page to access their content.
File objects are generally retrieved from a FileList object returned as a result of a user selecting files using the <input> element, from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement."
For more info and code examples, see the sample demo linked from the same article.
This might not be what you're trying to do, but someone out there may find it helpful:
If you want to share a link (by email for example) to a network file you can do so like this:
file:///Volumes/SomeNetworkFolder/Path/To/file.html
This however also requires that the recipient connects to the network folder in finder --- in menu bar,
Go > Connect to Server
enter server address (e.g. file.yourdomain.com - "SomeNetworkFolder" will be inside this directory) and click Connect. Now the link above should work.
Here is the alternative way to download local file by client side and server side effort:
<a onclick='fileClick(this)' href="file://C:/path/to/file/file.html"/>
js:
function fileClick(a) {
var linkTag = a.href;
var substring = "file:///";
if (linkTag.includes(substring)) {
var url = '/v/downloadLocalfile?path=' +
encodeURIComponent(linkTag);
fileOpen(url);
}
else {
window.open(linkTag, '_blank');
}
}
function fileOpen(url) {
$.ajax({
url: url,
complete: function (jqxhr, txt_status) {
console.log("Complete: [ " + txt_status + " ] " + jqxhr);
if (txt_status == 'success') {
window.open(url, '_self');
}
else {
alert("File not found[404]!");
}
// }
}
});
}
Server side[java]:
#GetMapping("/v/downloadLocalfile")
public void downloadLocalfile(#RequestParam String path, HttpServletResponse
response) throws IOException, JRException {
try {
String nPath = path.replace("file:///", "").trim();
File file = new File(nPath);
String fileName = file.getName();
response.setHeader("Content-Disposition", "attachment;filename=" +
fileName);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
response.setStatus(200);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
// out.flush();
in.close();
out.close();
}
else {
response.setStatus(404);
}
} catch (Exception ex) {
logger.error(ex.getLocalizedMessage());
}
return;
}
You can expose your entire file system in your browser by using an http server.
caddy2 server
caddy file-server --listen :2022 --browse --root /
serves the root file system at http://localhost:2022/
python3 built-in server
python3 -m http.server
serves current dir on http://localhost:8000/
python2 built-in server
python3 -m SimpleHTTPServer
serves current dir on http://localhost:8000/
This s
I've an extension which saves some files to the downloads folder. The code below is just for testing
//This lies in the background page of my extension
function fileTest(name) {
var a = document.createElement('a');
a.href = 'data:text/plain;base64,SGVsbG8gV29ybGQh'; //Hello World!
a.download = name + '.txt';
a.onclick = function (e) {console.log('[TEST] ' + name);return true;};
a.click();
}
window.onload = function() {
fileTest('test1');
fileTest('test12');
fileTest('test123');
}
only the first file "test1.txt" is saved to the disk, although the output of the console shows that there was 3 clicks
[TEST] test1
[TEST] test12
[TEST] test123
Is this an intentional limitation by the browser ? or there's something wrong with the code ?
When I run your code in a regular browsing session, I get a slide out notification (at the top of the window) that says
This site is attempting to download multiple files. Do you want to allow this?
So, yes, it is a security limitation of the browser to restrict downloads that are not user-initiated. You probably don't see the notification because the action is being performed by your background page.
The limitation seems to be one download per user action as demonstrated in this variant of your code:
window.onclick = function() {
fileTest('test1');
}
This will allow unlimited downloads, but only one download per click event.
I'm trying to link to a local file. I've set href as follows:
Link Anchor
In Firefox, when I right click and "open link in new tab", nothing happens.
When I right click and "copy link location", then manually open a new tab and paste the copied link, it works fine. So it seems my file:// syntax is fine. I've also tried it with 3 slashes like file:/// but it's the same result.
What am I doing wrong?
By definition, file: URLs are system-dependent, and they have little use. A URL as in your example works when used locally, i.e. the linking page itself is in the user’s computer. But browsers generally refuse to follow file: links on a page that it has fetched with the HTTP protocol, so that the page's own URL is an http: URL. When you click on such a link, nothing happens. The purpose is presumably security: to prevent a remote page from accessing files in the visitor’s computer. (I think this feature was first implemented in Mozilla, then copied to other browsers.)
So if you work with HTML documents in your computer, the file: URLs should work, though there are system-dependent issues in their syntax (how you write path names and file names in such a URL).
If you really need to work with an HTML document on your computers and another HTML document on a web server, the way to make links work is to use the local file as primary and, if needed, use client-side scripting to fetch the document from the server,
Organize your files in hierarchical directories and then just use relative paths.
Demo:
HTML (index.html)
<a href='inner/file.html'>link</a>
Directory structure:
base/
base/index.html
base/inner/file.html
....
The href value inside the base tag will become your reference point for all your relative paths and thus override your current directory path value otherwise - the '~' is the root of your site
<head>
<base href="~/" />
</head>
This can happen when you are running IIS and you run the html page through it, then the Local file system will not be accessible.
To make your link work locally the run the calling html page directly from file browser not visual studio F5 or IIS simply click it to open from the file system, and make sure you are using the link like this:
Intro
../htmlfilename with .html
User can do this
This will solve your problem of redirection to anypage for local files.
Try swapping your colon : for a bar |. that should do it
Link Anchor
The right way of setting a href=“” when it's a local file.
It will not make any issue when code or file is online.
FAQ
Hope it will help you.
Here is the alternative way to download local file by client side and server side effort:
<a onclick='fileClick(this)' href="file://C:/path/to/file/file.html"/>
Js:
function fileClick(a) {
var linkTag = a.href;
var substring = "file:///";
if (linkTag.includes(substring)) {
var url = '/cnm/document/v/downloadLocalfile?path=' + encodeURIComponent(linkTag);
fileOpen(url);
}
else {
window.open(linkTag, '_blank');
}
}
function fileOpen(url) {
$.ajax({
url: url,
complete: function (jqxhr, txt_status) {
console.log("Complete: [ " + txt_status + " ] " + jqxhr);
if (txt_status == 'success') {
window.open(url, '_self');
}
else {
alert("File not found[404]!");
}
// }
}
});
}
Server side[java]:
#GetMapping("/v/downloadLocalfile")
public void downloadLocalfile(#RequestParam String path, HttpServletResponse
response) throws IOException, JRException {
try {
String nPath = path.replace("file:///", "").trim();
File file = new File(nPath);
String fileName = file.getName();
response.setHeader("Content-Disposition", "attachment;filename=" +
fileName);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
response.setStatus(200);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
// out.flush();
in.close();
out.close();
}
else {
response.setStatus(404);
}
} catch (Exception ex) {
logger.error(ex.getLocalizedMessage());
}
return;
}