I'm trying to create an automated script that lets me download various files from a website, then upload them to a new website. The script will let multiple users copy content from the old site to the new one at the same time.
I initially attempted to use AJAX to download one file at a time, and store the file(s) data in variables, then upload this variable (file data) to the second domain. The download worked fine, but the PHP page on the second domain always threw back a 500 request error message AFTER uploading, despite setting various file size parameters and processing time parameters in PHP. This meant I couldnt even see what was echoed by the PHP page to debug, and continue developing that method.
After spending a long time trying to fix this (and failing miserably), I decided to just let the users download the old files normally, then use a form to upload the files. As I want the script to continue to run whilst the file is uploading, I've decided to set the forms target to "_blank" to open a new tab (which uploads the file).
How can I retrieve the windows handle that's opened with the target="_blank" form, to test when the window is closed? I don't need to access the windows HTML, I just want to check when it closes. The page that's opened by the form is not on the same domain as the form that opens it, but the "Access-Control-Allow-Origin" header is set to "*" on the second domains PHP page.
I don't think you can retrieve the window handle, but you can use Javascript to keep a reference to the window and check whether the window is closed or not. You would have to open your window with Javascript like this
var uploadWindow = window.open("http://www.google.com");
Then you can use a function on a timer to monitor if the window has closed or not:
var interval = 250;
setTimeout(checkClose, interval);
function checkClose() {
if (uploadWindow.closed) {
// Code to run when window is closed
}
else {
setTimeout(checkClose, interval);
}
}
I hope this can be of help
Related
Background
In our company, we install our offline documentation topics (thousands of .htm files in a folder) on our users' computers. Users view our documentation offline through their browser using the file:/// protocol.
I have a banner that appears in the footer of each .htm file that asks users to decide whether we can track user analytics (via Application Insights). Once they make their choice, we don't show the banner.
My Goal and Overall Problem
My goal is to store their choice in the browser's local storage. I can do that just fine, but the problem is this:
These are offline .htm files. There is no website domain. So, the key and value for any local storage is stored only for the .htm file they are on at the time they make their choice. If they come back to a topic they made their choice on, then yes, my script can retrieve their choice. But if they navigate to another topic in our documentation system (another .htm file), the local storage key and value don't persist to those other topics, and my script doesn't know what they chose--so then the banner pops up again.
My Workaround Idea
I doubt this is the best approach, but not having a lot of experience and not knowing what else to try, necessity becomes the mother of invention.
Here's what I'm trying:
Have my local storage requests go through a single .htm file called storage.htm, thereby getting around the above problem by always having a single point of contact (storage.htm) with the local storage.
storage.htm loads via a blank iframe.
The iframe is tacked onto each .htm topic.
When a topic .htm loads, the iframe also loads and any functions inside it become (hopefully) available for use by my main script.
When users click on the banner, I send the choice as query parameters through my main script to the iframe's src.
storage.htm contains a parseQuery() function, and inside that function, it parses any query params and then does the actual localStorage.getValue(key) and localStorage.setValue(key,value) requests.
I then want to somehow force the iframe to refresh with those parameters and then call the parseQuery() function there from my main script.
My Code
From my main script:
Attempt 1:
I've tried the top-voted item from this thread,
How to check if iframe is loaded or it has a content?
but I get stuck inside the checkIfFrameLoaded() function, and it continues to loop through the check to see if the iframe is loaded. It never loads. I think it's because the contentWindow and/or contentDocument don't work with my offline files, so I won't bore you with that code.
Attempt 2:
This is what I'd like to do as it seems cleaner:
function doIframeStorage(type,key,value){
// We get a handle on the iframe's id of 'storage'.
let storage = document.querySelector('#storage');
const src = storage.getAttribute('src');
let query = src;
if (type==='get'){
query = src + `?type=${type}&key=${key}`;
} else if (type==='set'){
query = src + `?type=${type}&key=${key}&value=${value}`;
}
storage.src = query;
storage.addEventListener('load', (e) => parseQuery());
}
But I'm running into a problem where my parseQuery() function (from storage.htm) is always undefined:
Uncaught ReferenceError: parseQuery is not defined
Is it possible to load and access my parseQuery() function from my main script like I'm doing? If so, how? I thought the addEventListener would ensure it was loaded and therefore the parseQuery() function would then be available.
Or Is there a better way to do what I'm attempting?
I have 5 html pages and a JavaScript function DoInitialConfiguration() in a JavaScript File. User can open any of the five html pages and I want that irrespective of which page is opened, I call this function on the first page access. But also want to remember that the function has been called once and not call it in other page load. I only have these 5 html pages and the JavaScript file which has the function. I am owner of the JavaScript file but can do limited change in the html pages (which I don't own) like load the JavaScipt file and call the function DoInitialConfiguration().
Since the JavaScript file will remain in browser cache, is there a way to remember the function has been called once by using any variable in the JS file. It is OK to call DoInitialConfiguration() again if the page is reloaded after clearing browser cache.
how can this functionality be achieved
If your 5 pages are hosted under same site (which probably would be the case), you can use localStorage to add a key to check if your script was called first time or not.
if (localStorage.getItem("firstRun") != null) {
// second run+ code goes here
} else {
localStorage.setItem("firstRun", "ohyes");
// first run code goes here
}
You can possibly use localStorage for this. Once your code executes set a localStorage variable i.e. localStorage.setItem(<key>, <value>) and in the function check if the localStorage has been set i.e. localStorage.getItem("lastname"). If its set do not execute the code.
It would be good to understand you setup and case study better.
If I understand you correctly, you have 5 separate HTML pages (and you are not running a Single Page Application [SPA]) then what you want to do is impossible through browser and cache memory alone. If you want to remember settings you need to save these using localStorage or cookies (as some of the answers popped up have suggested) but as they are 5 different html pages what does the Js do to make you not want to re-run it on a second page load?
I want to execute two operations in one javaScript function
force download of a csv file
send an ajax request to mark records in table that records were downloaded.
Since both of these operations will present the user with prompts and dialogue boxes, I want to delay execution of the 2nd event until the first event is complete.
When the user opens the page, they are presented with a list of current records. They check records they wish to process. The checked records are then packaged and the user is presented with the download "Save" or "Open" box. when that operation is complete then the ajax request should execute.
My thought was I could detect when "a" was removed from the document. But I'm not sure how I would do that.
Here is my code for the download
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(exportArray, {type: 'text/csv'}));
a.download = 'jobCostHandOff.csv';
// Append anchor to body.
document.body.appendChild(a)
a.click();
// Remove anchor from body
document.body.removeChild(a)
I have implemented such a mechanism in a web application with the following workflow:
the user selects a file on their computer
they configure options of the app
they click the submit button
a loader starts animating client-side
the browser send the entire form to the server for processing
the processing (which is actually about converting a guitar score to a tablature) yields a text/plain file, which is stored on the server (but not sent yet): a small JSON with the link to the generated file is sent back. That JSON data represents either success or error. In the case of error, the message is displayed to the user. In the case of success, the status field is set to OK and the payload contains the link to the file.
the JS code handling the AJAX call, upon success, triggers the download.
the browser presents the user with the usual (e.g. in Firefox) "open or save file" dialog
the web app detects the opening of the dialog and hides the loader.
It seems pretty similar to your need.
The gist of the solution is this:
triggering the file download is done by setting the src attribute of an iframe hidden in the page
the server sends a cookie in response to the request for the file to be downloaded
a JS code on a timer inspects the cookies of the document (which, very fortunately, includes the cookies to the iframe) and upon seeing "the Holy cookie", knows for sure that the file download has started, which is the only event the code can grab.
Quickly looking through the PHP code of my web app, I see this:
// This cookie is for the jQuery.fileDownload plugin
header('Set-Cookie: fileDownload=true; path=/');
You have the name of the JS code that does the last bullet point item in the code comment :-) Another reason among the myriad of reasons why I write commented code...
HTH.
I have a button that lets users download a file.
The file is returned from the server in the Response (binaries set as attachment), and I am letting the browser handle the file download from there on out.
Im doing the following on button click:
var fileUrl = 'mysite.com?id=12345';
document.location.href = fileUrl;
This will load the file, however, it can take a couple of seconds. I would like to show a preloader but then ofcourse I have to know when the file has been downloaded completed. Since I'm staying on the same page, is there a method or callback that tells if the 'new' location is loaded and thus I can hide the preloader?
Thanks!
Assuming you can download the file twice, you could load the file in a hidden iframe and detect when the iframe is done loading. Then, the file is already cached and should download quickly.
I am administrating a web page were we have an HTML dokument linking to PDF-files. The PDF-files gets updated from time to time, but we don't want to change the file names. This means that the users get old cached copies of the files, and have to refresh the files manually in order to get the newest file.
I added the following code to the links:
onClick="this.href=this.href.split('?')[0]+'?'+new Date().getTime()">
This solved the problem were the users got old files, but introduced a problem were the user needs to load PDFs even though they have not been updated. This causes more server load, and longer wait times for the users. Is it possible to get a similar code were the script checks a hash or the file size of the target file and adds that to the URL behind the questionmark? If this is possible I would overcome all my problems.
I dont know where you got access to but i assume you can use php.
So you should append an md5 (generated by md5_file()) as parameter to your string. The parameter will only change, if you upload a new pdf (mtime() will have the same effect)