create file upload that work in IE - javascript

I want to write a file upload script that works in IE but the two types of code that I'm writing have problems in IE.
Please help. How can you write a file upload script that works in IE?
Type 1
Problem Not Support File Api In IE (Is the trick not to use it?)
<!DOCTYPE html>
<html>
<head runat="server">
<title></title>
<script src="Scripts/jquery-1.6.2.js" type="text/javascript"></script>
<script type="text/javascript">
function updateSize() {
var nBytes = 0;
var nFiles=0;
oFiles = document.getElementById("uploadInput").files;
nFiles = oFiles.length;
for (var nFileId = 0; nFileId < nFiles; nFileId++) {
nBytes += oFiles[nFileId].size;
}
var sOutput = nBytes + " bytes";
// optional code for multiples approximation
for (var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; nApprox > 1; nApprox /= 1024, nMultiple++) {
sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";
}
document.getElementById("fileNum").innerHTML = nFiles;
document.getElementById("fileSize").innerHTML = sOutput;
}
// end of optional code
</script>
</head>
<body>
<form id="form1" runat="server">
<p><input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple /> selected files: <span id="fileNum">0</span>; total size: <span id="fileSize">0</span></p>
<p><input type="submit" value="Send file"></p>
</form>
</body>
</html>
Type 2
Problem Not Support document.getElementById('fileToUpload').files[0](Is the trick not to Get Files[0]?)
<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script type="text/javascript">
function fileSelected() {
var file = document.getElementById('fileToUpload').files[0];
if (file) {
var fileSize = 0;
if (file.size > 1024 * 1024)
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
else
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
}
}
function uploadFile() {
var fd = new FormData();
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
$.post("UploadHandler.ashx");
//xhr.open("POST", "UploadHandler.ashx");
xhr.send(fd);
}
function uploadProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
document.getElementById('prog').value = percentComplete;
}
else {
document.getElementById('progressNumber').innerHTML = 'unable to compute';
}
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert(evt.target.responseText);
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
alert("The upload has been canceled by the user or the browser dropped the connection.");
}
</script>
</head>
<body>
<form id="form1">
<div>
<label for="fileToUpload">
Select a File to Upload</label>
<input type="file" name="fileToUpload[]" id="fileToUpload" onchange="fileSelected();" />
</div>
<div id="fileName">
</div>
<div id="fileSize">
</div>
<div id="fileType">
</div>
<div>
<input type="button" onclick="uploadFile()" value="Upload" />
</div>
<div id="progressNumber">
</div>
<progress id="prog" value="0" max="100.0"></progress>
</form>
</body>
Please Help :(

You can't use these functions unless you're using IE10 or another modern browser. Workarounds are possible for earlier versions of Internet Explorer (and other browsers), but you'll need to adjust your back-end code too.
Why it doesn't work
Internet Explorer up until version 10 doesn't support a number of these features, the key ones being the FormData and FileReader APIs. Both of your code snippets rely on the FileReader API, and the second one also relies on FormData to upload the file dynamically.
How to determine whether to execute the code or not
I recently wrote a file upload widget that detected these features and served different code depending on support. I used the feature detections from Modernizr, because it's tests are regularly put to the test by the open source community:
var support = {
// Are files exposed to JS?
// As used by Modernizr #
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/file/api.js
'fileReader' : (function testFileReader(){
// Test: look for global file class.
return !!(window.File && window.FileList && window.FileReader);
}()),
// AJAX file upload via formData?
'formData' : window.FormData !== void 0
};
For your fileSelected function, you'll need support.fileReader to evaluate true; for uploadFile, you need support.formData.
A workaround for browsers that don't support these features
Without these features it's impossible to read a file from the front-end or to send a file using AJAX. What you can do, though, is send your file via a hidden <iframe/> inside your current page, and get UploadHandler.ashx to respond differently to non-XHR requests.
This solution is technically synchronous (just happening in another, hidden page), so you won't get updates — the only feedback is when the upload is complete and the server has responded. So you will only be able to inform the user as to file name, size, and success once they have completely uploaded it — which might take a while!
Anyway, the HTML for this would look as follows:
<form
id="form1"
runat="server"
action="UploadHandler.ashx"
target="fileIframe">
<iframe
name="fileIframe"
style="display:none"
onload="parseIframeResponse"
tabindex="-1">
</iframe>
<p>
<input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple />
selected files:
<span id="fileNum">
0
</span>
; total size:
<span id="fileSize">
0
</span>
</p>
<p>
<input type="submit" value="Send file">
</p>
</form>
A few changes:
The form now has a target, which means that when it posts its content to the URI in action, it will load the response in there, as opposed to on the current page.
The target is a name reference to an iframe we've included. It is hidden with display:none, and given a negative tabindex just to make sure the user doesn't stumble into it. It also has an onload property specified. This is the only way of binding functions to the load event in older versions of IE.
So when the form is submitted, we stay on the current page and the server response loads in our hidden iframe. When that happens, the browser will execute the function named in the onload attribute. Sadly, this means that function needs to be in the global scope!
Back-end stuff
I don't know how your back-end works, but if the iframe is to load the response instead of downloading it, it will need to be HTML or plain text (and that will need to be specified in the mime-type). You can tell whether the form was posted via AJAX from the back-end by looking for the X-Requested-With header, which should have a value of XMLHttpRequest — if that isn't there, then the iframe is asking for the response and you need to send text or HTML. You may want to stringify a JSON response that exposes the values you wanted to feed back to the user like fileName, fileSize & fileType. I'm hoping you can do this yourself or get a colleague to handle it.
Capturing the iframe response
As mentioned, the response handler function will need to be in the global scope for the onload attribute to bind to, because of old IE being very quirky. I see you're using jQuery, so if you went down the route of stringifying the server response, you could write this function as follows:
function parseIframeResponse(){
var response = $('#fileIframe').contents().find('body').text();
var object = $.parseJSON(response);
}
Issues with the iframe load event binding
As mentioned earlier, the iframe load event needs to be bound inline as an attribute of the iframe itself — this is because IE will simply fail to register it otherwise. But this is problematic in and of itself because even an empty iframe (an empty or non-present src will default to about:blank) fires a load event. To mitigate this you will need to discard any response that evaluates to an empty string as a false positive, and make sure your back-end responds with some content even if it encounters a fault.
Presumably, you would then want to use whatever information is in there to execute some of the code you've currently got in the functions fileSelected, uploadProgress, etc.
Hope this helps.
EDIT 1: Out-of-the-box solutions
In hindsight, despite writing this off the back of having developed my own solution to the problem, it could be considered negligent not to mention Fine Uploader, a heavily tested (over 700 closed issues!) and well maintained stand-alone plugin that aims to achieve the best file upload experience possible for IE7 and up. There's also a good selection of back-end server components — including ASP.NET — to parse the upload. You might find it easier to tweak this than roll your own!
EDIT 2: Neglected to mention issues with iframe's load event. Amended answer in place.

Related

Change programmatically IID_IHTMLInputFileElement value

I tried for several days to programmatically put a file path into a input type file element into a CHtmlView control (IE). I have tried this:
IHTMLInputFileElement* pInputElem = NULL;
hr = pElemDispatch->QueryInterface(IID_IHTMLInputFileElement, (void**)&pInputElem);
CString sFile(_T("C:\\Flaviu\\SomeFile.txt"));
BSTR bstrFilesAttribute = sFile.AllocSysString();
hr = pInputElem->put_value(bstrFilesAttribute); // hr is S_OK though
SysFreeString(bstrFilesAttribute);
but didn't work, I mean there is no SomeFile.txt chosen on input file.
I have read on several sites that I cannot edit or set value on an input type file element for security reason.
Somewhere, someone, suggested a simple solution: to make a copy of the original web page, and edit html source code and replace input type file element to an input type text. Which I have done. I only have to solve "action" attribute on form:
Original html source code:
<form name="uf" method="POST" action="/WS6ERT/SomeFile.do" enctype="multipart/form-data">
<div style="background-color: #c6c6c6; padding: 5px">
<span>Choose file:</span> <span> <input type="file" name="linkdoc" size="75" value=""></span><span><input type="submit" value="Send"></span>
</div>
</form>
and I made a copy, and I replaced input type file, with input type text:
<form name="uf" method="POST"
action="https://originalsite.com/WS6ERT/SomeFile.do" enctype="multipart/form-data">
<div style="background-color: #c6c6c6; padding: 5px">
<span>Choose file::</span> <span> <input type="text" name="linkdoc">
</span><span><input type="submit" value="Send"></span>
</form>
The important tags attribute: "action="
Of course that is not correct what I have written in my html source, because my path is pointing on the original file, which I didn't edit...
Is there a way to solve this issue? To put programmatically a file path into an input type file on a CHtmlView view? Or how to overcome this problem?
Last Edit: Can I setup the file with javascript ? I saw here: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-files that is possible to setup a file in files attribute. But I don't know how to do that ...
If you have a handle to CHtmlView* then use CHtmlView::Navigate2 or CHtmlView::Navigate
This should do the job unless html control is busy with a previous request, for example you already made a Navigate request and the html control is not finished processing that request. In the case, you can override CHtmlView::OnNavigateComplete2, which lets you know the html control is finished with the previous navigation request, and it can receive a new request. Alternatively you could use a wait function to wait for the control to finish using the for loop shown below.
CString filename = _T("C:\\Test\\test.html");
CStringW content = LR"(<html><body> content </body></html>)";
//optional: in case the control is busy with previous request
for(int i = 0; i < 100; i++)
{
MSG msg;
while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
if(!AfxGetThread()->PumpMessage())
break;
CFile test;
if(test.Open(filename, CFile::modeNoTruncate | CFile::modeWrite))
break;
}
CFile fout;
if(fout.Open(filename, CFile::modeCreate | CFile::modeWrite))
{
content = LR"(<html><body> content UPDATE </body></html>)";
CStringA utf8 = CW2A(content, CP_UTF8);
fout.Write(utf8, utf8.GetLength());
fout.Close();
htmlview->Navigate(filename, 0, NULL);
}

JavaScript Automatically Save Image File to Folder

How can I automatically save an image from canvas into a folder? I am using the
signature_pad-1.5.2 from szimek (link). Here is what I have tried so far:
HTML CANVAS
<div id="signature-pad" class="m-signature-pad">
<div class="m-signature-pad--body">
<canvas></canvas>
</div>
<div class="m-signature-pad--footer">
<div class="description">Signature</div>
<button type="button" class="button clear" data-action="clear">Clear</button>
<button type="button" class="button save" data-action="save">Save</button>
</div>
</div>
<script src="js/signature_pad.js"></script>
<script src="js/app.js"></script>
The signature_pad.js is for drawing in the canvas. Here is the content of my app.js from signature_pad-1.5.2 (I modified it a little):
app.js
var wrapper = document.getElementById("signature-pad"),
clearButton = wrapper.querySelector("[data-action=clear]"),
saveButton = wrapper.querySelector("[data-action=save]"),
canvas = wrapper.querySelector("canvas"),
signaturePad;
saveButton.addEventListener("click", function (event) {
if (signaturePad.isEmpty()) {
alert("Please provide signature first.");
} else {
newfolder = myObject.CreateFolder ("C:\\xampp\\htdocs\\signature\\resources\\sigs");
alert();
saveButton.href = signaturePad.toDataURL();
saveButton.download = 'image.png';
}
});
I am trying to save the image.png file to newFolder when I click the save button. Thanks
There is no way for javascript to access the filesystem, this is due to security concerns. You can store the image data as a string in a lot of places though, such as browser storage. Luckily for you it looks as though you're trying to store it in a web server's folder!
The best thing for you to do here is to make a script on the server that you want to store the image on. That script will accept a file POST request and store it in a server folder somewhere. This can be written in php for example.
Once you have that server-side script, make an AJAX request from the client (from the javascript) with the image data to that server script.
I would provide code samples and a more in-depth explanation, but unfortunately you haven't provided any real info about your tech stack and what exactly you're trying to accomplish. Good luck!

How can I detect IE9 or below then execute some PHP based on the outcome?

I know how to detect the browser using javascript, but how can I pass this information to PHP?
How can I do the following:
Javascript detects the browser, returns 'yes' if the user has IE 9 or below and moves to step 2.
Javascript communicates 'yes' to PHP and moves to step 3.
PHP executes an if / else statement based on whether or not a 'yes' from javascript above is present.
User Agent is not a reliable method.
Personally I use an Agent Switcher to fool websites quite often.
This method would not be fooled.
My only option would be to disable JavaScript.
Pick a JS instruction that works in IE9+ and not previous versions
There is probably a better instruction to use other than getElementsByClassName but it demonstrates the concept.
Pick an instruction form a test page like this:
Browser Capability Tests
Then build a test page and test that page on a Cross Browser Test site.
This test will properly pass (TRUE) or fail (FALSE) based on Browser support for try{}catch{} on any Browser going back to 1999:
Netscape 6.0
FireFox 1.0
IE 5.5
It will Pass TRUE on:
Chrome
FireFox 3.0+
IE9+
Opera
Safari
Will fail (FALSE) only on IE5.5 - IE8
HTML
<div class="test"></div>
JS
var checkIE = false;
try {
var el = document.getElementsByClassName('test');
checkIE9 = true;
}
catch(e) {
checkIE9 = false;
}
Then redirect based whether checkIE9 is true or false
Replace mozilla.org with the IE9 page/script and microsoft.com with the old style page/script
if (checkIE9){
window.location = 'http://mozilla.org';
}
else{
window.location = 'http://www.microsoft.com';
}
Or submit a form based on true or false.
HTML
<form action="true.php" method="get"><div>
<input type="hidden" name="chkIE" value="1"/>
<button id="t" type="submit"></button>
</div></form>
<form action="false.php" method="get"><div>
<input type="hidden" name="chkIE" value="2"/>
<button id="f" type="submit"></button>
</div></form>
NOTE: Yes it could be one form with two buttons but forms are cheap, and I like to pass values with hidden inputs.
I did not use zero as a value in case the a user were to go direct to the page the forms link to.
Zero Check Code in the test.php:
$chckIE9 = intval($_GET['chkIE9']);
if($chckIE9 == 0){
include('test.html');
exit;
}
Or if you may want an intermediate page and link both true and false to the same script.
<form action="test.php" method="get"><div>
<input type="hidden" name="chkIE" value="1"/>
<button id="t" type="submit"></button>
</div></form>
<form action="test.php" method="get"><div>
<input type="hidden" name="chkIE" value="2"/>
<button id="f" type="submit"></button>
</div></form>
PHP:
$chckIE9 = intval($_GET['chkIE9']);
if($chckIE9 == 1){
include('true.php');
}
elseif($chckIE9 == 2){
include('false.php');
}
else{
include('test.html');
}
exit;
JS
Here a decision must be made as to which way to default.
You could click 'f' if (!checkIE9)
Then default would be the IE9+
If there is a need to default it is probably better to default to the false
if (checkIE9){
document.getElementById('t').click();
}
else{
document.getElementById('f').click();
}
Snipppet
This snippet will display either "IE9+ Compatible" or "UPDATE YOUR BROWSER"
This code is tested with IE8 which pops up "UPDATE YOUR BROWSER"
var checkIE = false;
try {
var el = document.getElementsByClassName('true');
checkIE9 = true;
}
catch(e) {
checkIE9 = false;
}
if (checkIE9){
document.getElementById('t').style.display = 'block';
}
else{
document.getElementById('f').style.display = 'block';
}
#t,#f,.hide{display:none;}
<!DOCTYPE html>
<html lang="en">
<head></head><body>
<div id="t" class="true"><h2> IE9+ Compatible</h2></div>
<div id="f"><h2> UPDATE YOUR BROWSER</h2></div>
</div>
<form action="test.php" method="get"><div><input type="hidden" name="chkIE" value="1"/><button class="hide" id="t" type="submit"></button></div></form>
<form action="test.php" method="get"><div><input type="hidden" name="chkIE" value="2"/><button class="hide" id="f" type="submit"></button></div></form>
</body></html>
$_SERVER['HTTP_USER_AGENT']
Contents of the User-Agent: header from the current request, if there
is one. This is a string denoting the user agent being which is
accessing the page. A typical example is: Mozilla/4.5 [en] (X11; U;
Linux 2.2.9 i586). Among other things, you can use this value with
get_browser() to tailor your page's output to the capabilities of the
user agent.
You can not pass information from Javascript to the PHP without any interaction with server e.g. refresh page or ajax. It is because javascript operate on content generated with PHP server and sent as response to the browser. If the browser obtain a response (content) try render it and then you can handle what browser does via javascript. At this time PHP server doesn't know who are you or what you want to do next without any request.
So if you want to do with refresh page, you can handle version via javascript and refresh page with updated url.
Use case tip:
client request to -> server = i want a normal page
server response to -> client = here is it
client browser parsing = ha js tell me what browser version
javascript -> IE9, ok so do refresh with my own parameter, add as GET parameter to url
client request to -> server = ha give me page with param = IE9, generating..
server response to -> client = here is it !!!

How to create callback for form submit event (without ajax)

I want to have a callback after my form has successfully been submitted. This form does not reload the page and the ajax alternative is not available to us because of "cross origin" issues.
What I have now is:
$('#uploadform form').on('submit', function(){
// DO STUFF HERE
});
But this is firing as soon as submit event is triggered and not as a callback. Without using ajax, how do I make code run after and only after the response is received (and get the response to do stuff with)? Is this even possible?
It is through AWS's S3 file hosting and cannot use JSONP.
I would rather not use an iframe if I don't have to for simplicity's sake.
EDIT
It doesn't reload the page just like a file download link doesn't reload the page. Otherwise it's exactly like any other form. It's not submitted inside of an iframe. It's a normal form, but the headers involved don't require the page to reload.
A solution has come to me that will allow me to submit my form without reloading the page, not use an iframe or JSONP, and while it probably technically counts as AJAX, it does not have this same "cross origin" issue.
function uploadFile() {
var file = document.getElementById('file').files[0];
var fd = new FormData();
fd.append('key', "${filename}");
fd.append("file",file);
xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
xhr.open('POST', 'http://fake-bucket-name.s3-us-west-1.amazonaws.com/', true); //MUST BE LAST LINE BEFORE YOU SEND
xhr.send(fd);
}
function uploadProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
}
else {
document.getElementById('progressNumber').innerHTML = 'unable to compute';
}
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert("Done - " + evt.target.responseText );
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file." + evt);
}
function uploadCanceled(evt) {
alert("The upload has been canceled by the user or the browser dropped the connection.");
}
With a simple form like this:
<form id="form1" enctype="multipart/form-data" method="post">
<div class="row">
<label for="file">Select a File to Upload</label><br>
<input type="file" name="file" id="file">
</div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
<input type="button" onclick="uploadFile()" value="Upload">
</div>
<div id="progressNumber"></div>
</form>
The uploadComplete(evt) function being the callback. As you can see, it also gives you the percentage complete you can show your users.
Note: To do this you have to set the correct upload policy and CORS
policy in your S3 account.
– RonSper
You will run into 'cross origin' issues with ajax and iframes equally if you need access to the response.
JSONP is the only way around your 'cross-origin' issues. It is what is used by all JSON APIs that are hosted on a different domain, unless you try to use CORS which isn't supported in legacy IE versions.
If you can control the server where the form is submitted you should be able to make it return a JSONP compatible response. If not, you are kind of out of luck.

to send a text file to server using javascript

I need to send a text file to server and get it saved. how can i do it using javascript???
There are all sorts of security issues surrounding this. Would you be happy to visit a website that would upload a file from your machine to the server?
For a generic website, where users are likely to have their permissions set to deny this sort of access it isn't possible.
If by chance, you are looking to do this for an application where you have control over the security settings for its users, and that you can guarantee its Windows and IE, then it is possible by reading the file and passing the details by posting to the server. See the following link : http://www.javascripter.net/faq/reading2.htm
However when you move away from IE or Windows, then you are going to struggle.
using ajax of course.
have a file on the server, PHP or ASP - depending on what your internet server is.
this file will accept the text file (data and name), and should also check for size and if this file already exists or not, and if all is ok- it will save it, and return a string "OK"
on the client, javascript side, just send the information to the server using ajax, or HTTPREQUST object - there's plentty of documentation for that around. and if you get back a response of "OK" then you know that it sent well.
even better: don't use HTTPREQUEST, but do dynmaic script tag insertion - where the source attribute of the script you're appending is that file on the server like:
var a = document.createElement('script');
a.type = 'text/javascript';
a.src = "http://server/serverFile.PHP?filename=XXX&data=LONG STRING OF DATA REPRESTING THE DATA TO BE SAVED PROBABLY LESS THAN 2K IN SIZE AND ALSO YOU SHOULD ESCAPE OR ATLEAST URIENCODE IT";
document.body.appendChild(a);
and on the server file, serverFILE.PHP:
<?php
// some code to save the request variable [data].
// if all is ok:
alert("ok")
// or:
result = "ok"
?>
get it?
note: you'll probably have a limit of less than 2K on the file size.
Javascript is a front-end language. You may use php or any server side language.
You can create an Ajax equiv function make an iframe with width and height=0px then make it the target of the form with the file upload input and process it with the action PHP
<form action="upload.php" target="target" method="post"
name="uploadform" id="uploadform" enctype="multipart/form-data">
<label for="input_file_upload">Upload:</label>
<input onchange="document.uploadform.submit();" size="80"
type="file" name="file_upload[]" id="file_upload"
multiple="multiple" />
<input type="hidden" name="fileUpload" value="upload" />
<input type="button" value="Upload" />
</form>
<iframe id="target" name="target" style="width: 0px; height: 0px;">
</iframe>

Categories