I am working on creating a file uploader, where the contents will be written to a remote server in chunks using a 3rd party API. The API provides a WriteFileChunk() method that takes 3 parameters, the target file path, the start position (Int64) and data (string) of bytes.
Each time FileReader receives a chunk of the maximum supported size (16kb), I need to use Ajax to pass this to a PHP file and write it using the API. I suspect that this should be done in the onprogress event of FileReader, however I am at somewhat of a loss given that I cannot find any similar examples.
What would be the best way to implement this using FileReader, ensuring that each chunk is uploaded before writing the next? If onprogress is the best choice, how can I get the current chunk data?
$(document).ready(function()
{
function uploadFile()
{
var files = document.getElementById('file').files;
if (!files.length)
{
alert('Please select a file!');
return;
}
var file = files[0];
var first_byte = 0;
var last_byte = file.size - 1;
// File Reader
var reader = new FileReader();
reader.onerror = function(evt)
{
switch(evt.target.error.code)
{
case evt.target.error.NOT_FOUND_ERR:
alert('File Not Found!');
break;
case evt.target.error.NOT_READABLE_ERR:
alert('File is not readable');
break;
case evt.target.error.ABORT_ERR:
break;
default:
alert('An error occurred reading this file.');
};
};
reader.onprogress = function(evt)
{
if (evt.lengthComputable)
{
var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
console.log(percentLoaded + "%");
if (percentLoaded < 100)
{
$("#upload_progress").progressbar('value', percentLoaded);
}
}
};
reader.onabort = function(evt)
{
alert('File Upload Cancelled');
};
reader.onloadstart = function(evt)
{
$("#upload_progress").progressbar({
value: 0,
max: 100
});
};
reader.onload = function(evt)
{
$("#upload_progress").progressbar('value', 100);
};
reader.onloadend = function(evt)
{
if (evt.target.readyState == FileReader.DONE) // DONE == 2
{
alert("Upload Complete!");
//console.log(evt.target.result);
}
};
var blob = file.slice(first_byte, last_byte + 1);
reader.readAsBinaryString(blob);
}
fileupload_dialog = $( "#dialog-fileupload" ).dialog(
{
autoOpen: false,
height: 175,
width: 350,
modal: true,
buttons:
{
"Upload File": uploadFile
},
close: function()
{
form[ 0 ].reset();
}
});
form = fileupload_dialog.find( "form" ).on( "submit", function( event )
{
event.preventDefault();
uploadFile();
});
$("#file_upload a").click(function()
{
event.preventDefault();
fileupload_dialog.dialog( "open" );
});
});
The main challenge here is that the FileReader will need to read the entire file into memory before it return any usable data to us via the result property, meaning you can't grab chunks from the file while the file is being read (and the progress event won't provide/point to any data):
This property [result] is only valid after the read operation is
complete [...]
Source
As the complete file is loaded into memory there wouldn't really be any benefits chunking the read process (if it was possible), besides from reducing a little lag perhaps between the two processes.
I would suggest the following approach based on the above:
Load the entire file into memory, but as ArrayBuffer
Calculate number of segments required (Math.ceil(fileLength/chunkSize))
Create a chunk using a Uint8Array view for the ArrayBuffer using the offset and chunk length arguments
Send the chunk, wait for response asynchronously, continue to next chunk until left length is <= 0 byte.
The chunk can be converted to a Blob before sending it, if needed:
var chunkBlob = new Blob([chunk], {type: "application/octet-stream"});
Example process
A pseudo server example waiting arbitrarily 100ms between each block of 16kb:
file.onchange = function(e) {
var fr = new FileReader();
fr.onprogress = function(e) {progress.value = e.loaded / e.total};
fr.onload = startUpload.bind(fr);
progress.style.display = "inline-block";
fr.readAsArrayBuffer(e.target.files[0]);
}
// Main upload code
function startUpload() {
// calculate sizes
var chunkSize = 16<<10;
var buffer = this.result;
var fileSize = buffer.byteLength;
var segments = Math.ceil(fileSize / chunkSize);
var count = 0;
progress.value = 0;
// start "upload"
(function upload() {
var segSize = Math.min(chunkSize, fileSize - count * chunkSize);
if (segSize > 0) {
var chunk = new Uint8Array(buffer, count++ * chunkSize, segSize); // get a chunk
progress.value = count / segments;
// send chunk to server (here pseudo cycle for demo purpose)
setTimeout(upload, 100); // when upload OK, call function again for the next block
}
else {
alert("Done");
progress.style.display = "none";
}
})()
}
body {font:16px sans-serif;margin:20px 0 0 20px}
<label>Select any file: <input type=file id="file"></label><br>
<progress id="progress" value=0 max=1 style="display:none" />
Related
I'm creating drag and drop field to upload images. Everything works fine, files are uploaded successfully, but I lack knowledge how to properly add error messages for different outcomes like - it fails to upload for some reason, folder doesn't exists, upload success/fail messages. And also I would like to add some code that would clear out preview(gallery) section of the code when starting new batch/multiple image upload.
Could some one point me to right direction and help to understand better what should I do next to achieve intended result?
<div id="drop-area">
<form class="my-form" method="post">
<input type="file" id="fileElem" name="upload_image" multiple accept="image/*" onchange="handleFiles(this.files)">
<label class="button" for="fileElem">Select some files</label>
</form>
<progress id="progress-bar" max=100 value=0></progress>
<div id="gallery" ></div>
</div>
// ************************ Drag and drop ***************** //
let dropArea = document.getElementById("drop-area")
// Prevent default drag behaviors
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false)
document.body.addEventListener(eventName, preventDefaults, false)
})
// Highlight drop area when item is dragged over it
;['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false)
})
;['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false)
})
// Handle dropped files
dropArea.addEventListener('drop', handleDrop, false)
function preventDefaults (e) {
e.preventDefault()
e.stopPropagation()
}
function highlight(e) {
dropArea.classList.add('highlight')
}
function unhighlight(e) {
dropArea.classList.remove('active')
}
function handleDrop(e) {
var dt = e.dataTransfer
var files = dt.files
handleFiles(files)
}
let uploadProgress = []
let progressBar = document.getElementById('progress-bar')
function initializeProgress(numFiles) {
progressBar.value = 0
uploadProgress = []
for(let i = numFiles; i > 0; i--) {
uploadProgress.push(0)
}
}
function updateProgress(fileNumber, percent) {
uploadProgress[fileNumber] = percent
let total = uploadProgress.reduce((tot, curr) => tot + curr, 0) / uploadProgress.length
console.debug('update', fileNumber, percent, total)
progressBar.value = total
}
function handleFiles(files) {
files = [...files]
initializeProgress(files.length)
files.forEach(uploadFile)
files.forEach(previewFile)
}
function previewFile(file) {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onloadend = function() {
let img = document.createElement('img')
img.src = reader.result
document.getElementById('gallery').appendChild(img)
}
}
function uploadFile(file, i) {
var xhr = new XMLHttpRequest()
var formData = new FormData()
xhr.open('POST', 'upload.php', true)
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
// Update progress (can be used to show progress indicator)
xhr.upload.addEventListener("progress", function(e) {
updateProgress(i, (e.loaded * 100.0 / e.total) || 100)
})
xhr.addEventListener('readystatechange', function(e) {
if (xhr.readyState == 4 && xhr.status == 200) {
updateProgress(i, 100) // <- Add this
}
else if (xhr.readyState == 4 && xhr.status != 200) {
}
})
formData.append('upload_image', file)
xhr.send(formData)
}
upload.php
$fileName = $_FILES['upload_image']['name'];
$fileType = $_FILES['upload_image']['type'];
move_uploaded_file($_FILES["upload_image"]["tmp_name"],"uploads/" .$fileName);
I have tried to put some echo's in upload.php for success message or fail, or just simple echo to at least output name of the file, but that brought no result at all. Not even single error message.
You are actually halfway to the goal you are pursuing. In your uploadFile(file, i) function, you are testing the HTTP status code returned by your PHP script. You updateProgress() when you receive a 200 status code (Success) and everything went good.
If something wrong happens with the file upload, PHP will store the error message in $_FILES['uploaded_file']['error'].
You can just check at the end of your script whether this value is equal to UPLOAD_ERR_OK (which means that the upload was successful) : in this case, your script should return a 200 status code (using PHP's built-in http_response_code()).
Else, set the status code to whatever you want (according to what the uploaded file's error message is, of course), and return this.
Your jQuery script will try to upload the file, receive an HTTP response with a set status code, and will accordingly continue with the execution, or show the error message you want to show based on the received status code (up to you to set the message).
I'm setting up web-based application using cakePHP, on one point i need to scan barcode then input the barcode result to text-input then run the calculation.
I want to open this web-based app on android tablet on its browser, then my idea is to provide button, on press it will open barcode scanner, then on scanning, it will insert the scanning result to the web-based app in the browser of the android tablet i have.
I tried to explore and find how to do it, but find none.
Is there any idea or insight if this possible? so I can only use 1 tablet device to run web-based system and run barcode scanner on that same tablet.
That is not quite possible in this case with PHP.
PHP is the script that runs on the server, doing things and/or dumping out data (HTML, files, JS, etc.) to the client's browser.
From what I understand, you want to run the barcode scanner on the client side, where it's not PHP that's running, but most likely Javascript.
You can do with JS inside HTML page.
For barcode scanning you need a barcodescanner.js file :
(function ($) {
$.fn.scannerDetection = function (options) {
// If string given, call onComplete callback
if (typeof options === "string") {
this.each(function () {
this.scannerDetectionTest(options);
});
return this;
}
// If false (boolean) given, deinitialize plugin
if (options === false) {
this.each(function () {
this.scannerDetectionOff();
});
return this;
}
var defaults = {
onComplete: false, // Callback after detection of a successfull scanning (scanned string in parameter)
onError: false, // Callback after detection of a unsuccessfull scanning (scanned string in parameter)
onReceive: false, // Callback after receiving and processing a char (scanned char in parameter)
onKeyDetect: false, // Callback after detecting a keyDown (key char in parameter) - in contrast to onReceive, this fires for non-character keys like tab, arrows, etc. too!
timeBeforeScanTest: 100, // Wait duration (ms) after keypress event to check if scanning is finished
avgTimeByChar: 30, // Average time (ms) between 2 chars. Used to do difference between keyboard typing and scanning
minLength: 6, // Minimum length for a scanning
endChar: [9, 13], // Chars to remove and means end of scanning
startChar: [], // Chars to remove and means start of scanning
ignoreIfFocusOn: false, // do not handle scans if the currently focused element matches this selector
scanButtonKeyCode: false, // Key code of the scanner hardware button (if the scanner button a acts as a key itself)
scanButtonLongPressThreshold: 3, // How many times the hardware button should issue a pressed event before a barcode is read to detect a longpress
onScanButtonLongPressed: false, // Callback after detection of a successfull scan while the scan button was pressed and held down
stopPropagation: false, // Stop immediate propagation on keypress event
preventDefault: false // Prevent default action on keypress event
};
if (typeof options === "function") {
options = { onComplete: options }
}
if (typeof options !== "object") {
options = $.extend({}, defaults);
} else {
options = $.extend({}, defaults, options);
}
this.each(function () {
var self = this, $self = $(self), firstCharTime = 0, lastCharTime = 0, stringWriting = '', callIsScanner = false, testTimer = false, scanButtonCounter = 0;
var initScannerDetection = function () {
firstCharTime = 0;
stringWriting = '';
scanButtonCounter = 0;
};
self.scannerDetectionOff = function () {
$self.unbind('keydown.scannerDetection');
$self.unbind('keypress.scannerDetection');
}
self.isFocusOnIgnoredElement = function () {
if (!options.ignoreIfFocusOn) return false;
if (typeof options.ignoreIfFocusOn === 'string') return $(':focus').is(options.ignoreIfFocusOn);
if (typeof options.ignoreIfFocusOn === 'object' && options.ignoreIfFocusOn.length) {
var focused = $(':focus');
for (var i = 0; i < options.ignoreIfFocusOn.length; i++) {
if (focused.is(options.ignoreIfFocusOn[i])) {
return true;
}
}
}
return false;
}
self.scannerDetectionTest = function (s) {
// If string is given, test it
if (s) {
firstCharTime = lastCharTime = 0;
stringWriting = s;
}
if (!scanButtonCounter) {
scanButtonCounter = 1;
}
// If all condition are good (length, time...), call the callback and re-initialize the plugin for next scanning
// Else, just re-initialize
if (stringWriting.length >= options.minLength && lastCharTime - firstCharTime < stringWriting.length * options.avgTimeByChar) {
if (options.onScanButtonLongPressed && scanButtonCounter > options.scanButtonLongPressThreshold) options.onScanButtonLongPressed.call(self, stringWriting, scanButtonCounter);
else if (options.onComplete) options.onComplete.call(self, stringWriting, scanButtonCounter);
$self.trigger('scannerDetectionComplete', { string: stringWriting });
initScannerDetection();
return true;
} else {
if (options.onError) options.onError.call(self, stringWriting);
$self.trigger('scannerDetectionError', { string: stringWriting });
initScannerDetection();
return false;
}
}
$self.data('scannerDetection', { options: options }).unbind('.scannerDetection').bind('keydown.scannerDetection', function (e) {
// If it's just the button of the scanner, ignore it and wait for the real input
if (options.scanButtonKeyCode !== false && e.which == options.scanButtonKeyCode) {
scanButtonCounter++;
// Cancel default
e.preventDefault();
e.stopImmediatePropagation();
}
// Add event on keydown because keypress is not triggered for non character keys (tab, up, down...)
// So need that to check endChar and startChar (that is often tab or enter) and call keypress if necessary
else if ((firstCharTime && options.endChar.indexOf(e.which) !== -1)
|| (!firstCharTime && options.startChar.indexOf(e.which) !== -1)) {
// Clone event, set type and trigger it
var e2 = jQuery.Event('keypress', e);
e2.type = 'keypress.scannerDetection';
$self.triggerHandler(e2);
// Cancel default
e.preventDefault();
e.stopImmediatePropagation();
}
// Fire keyDetect event in any case!
if (options.onKeyDetect) options.onKeyDetect.call(self, e);
$self.trigger('scannerDetectionKeyDetect', { evt: e });
}).bind('keypress.scannerDetection', function (e) {
if (this.isFocusOnIgnoredElement()) return;
if (options.stopPropagation) e.stopImmediatePropagation();
if (options.preventDefault) e.preventDefault();
if (firstCharTime && options.endChar.indexOf(e.which) !== -1) {
e.preventDefault();
e.stopImmediatePropagation();
callIsScanner = true;
} else if (!firstCharTime && options.startChar.indexOf(e.which) !== -1) {
e.preventDefault();
e.stopImmediatePropagation();
callIsScanner = false;
} else {
if (typeof (e.which) != 'undefined') {
stringWriting += String.fromCharCode(e.which);
}
callIsScanner = false;
}
if (!firstCharTime) {
firstCharTime = Date.now();
}
lastCharTime = Date.now();
if (testTimer) clearTimeout(testTimer);
if (callIsScanner) {
self.scannerDetectionTest();
testTimer = false;
} else {
testTimer = setTimeout(self.scannerDetectionTest, options.timeBeforeScanTest);
}
if (options.onReceive) options.onReceive.call(self, e);
$self.trigger('scannerDetectionReceive', { evt: e });
});
});
return this;
}
})(jQuery);
For usecase inside a HTML :
<script type="text/javascript">
$(document).scannerDetection({
timeBeforeScanTest: 200, // wait for the next character for upto 200ms
startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
onComplete: function(barcode, qty) {
console.log(barcode);
console.log(qty);
// barcode number code
// qty scanned by barcode scanner
},
onKeyDetect: function(event) {
return false;
}
});
</script>
I tried to make script ajax + php to upload files using put method, it is uploading, but the problem is, it makes the uploaded file no longer accessible.
sample original file :
test
uploaded file :
------WebKitFormBoundaryfHeuzHdIUxsjGOUb
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
test
------WebKitFormBoundaryfHeuzHdIUxsjGOUb--
as you can see if file is video/zip or any other file, it sure will broken.
here is my code
sendFile: function(files, index) {
if ($('a[data-parent="#accordion"]').size() != 0) {
var numRow = $('a[data-parent="#accordion"]').size();
}
else {
var numRow = index;
}
var progress = $('li[data-image="'+files[index].name+'_'+files[index].unique+'"]');
// File size validation
if (files[index].size >= 49999999) { // 49.999.999 = 50Mb max
progress.html('<strong style="color: red;">Cancelled</strong>');
progress.parent().next().html('File Size Exceeded! (MAX:50Mb)');
console.log("File size Exceeded!");
dragNdrop.prepare(files, index+1);
return false;
}
// begin upload
var formData = new FormData();
formData.append('file', files[index]);
var xhr = new XMLHttpRequest();
xhr.open('put', 'ajax/upload', true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("X-File-Name", files[index].unique);
xhr.onload = function() {
progress.find('.filestatus').html('<img src="assets/img/wait.gif">').fadeIn(200);
}
xhr.upload.onprogress = function (event) {
// too long to display
}
xhr.send(formData);
how can i upload file using my script without broken it ?
thanks in advance!
I am creating a real-time graph with flot library and using jquery $.get function.
I want the graph to be updated every 5 seconds retrieving the recorded data.
The X axis is in time mode. I have been trying to retrieve the necessary data but i can't get it yet. The .php file is fine because it connects to the postgresql database and writes the data into the requested variable.
I think that my problem is in the $.get function.
Can you please help me to find if my Javascript code is fine?
Thanks in advance
<script type="text/javascript">
$(function () {
var data=[];
var data_inicial = [];
var data_actual = [];
var x;
var y;
function data_init()
{
$.get("param_pozos_linea1.php", function(data1) { x= data1; });
data_inicial.push([x]);
return data_inicial;
}
function actualiza_data()
{
$.get("param_pozos_linea2.php", function(data2) { y= data2; });
data_actual.push(y);
return data_actual;
}
// control de velocidad
var updateInterval = 500;
$("#updateInterval").val(updateInterval).change(function () {
var v = $(this).val();
if (v && !isNaN(+v)) {
updateInterval = +v;
if (updateInterval < 1)
updateInterval = 1;
$(this).val("" + updateInterval);
}
});
// setup plot
var options = {
series: { shadowSize: 0 }, // drawing is faster without shadows
yaxis: { min: 0, max: 100 },
xaxis: { mode: "time",tickLength: 5, timeformat: "%d/%m - %h:%M %p"}
};
var plot = $.plot($("#placeholder"), data_init() , options);
function update() {
plot.setData([ actualiza_data() ]);
plot.draw();
setTimeout(update, updateInterval);
}
update();
});
</script>
The retrieved data from "param_pozos_linea1.php" file loooks like this:
[1355767803000,0],[1355767502000,0],[1355767202000,0],[1355766902000,0],[1355766602000,0],[1355766302000,0],[1355766002000,0],[1355765702000,0],[1355765402000,0],[1355765103000,2570.17],[1355764803000,2569.63]
And the retrieved data from "param_pozos_linea2.php" looks like this:
[1355767803000,0]
The get request is asynchronous, it is impossible for it to work in a synchronous manner like you think it does.
function data_init()
{
$.get("param_pozos_linea1.php", function(data1) { x= data1; }); <-- calls the server asynchronously
data_inicial.push([x]); <-- is called before code is set on server, so it is setting it with what ever the last value was
return data_inicial; <-- returns something you do not want
}
what you want to do is call the function that set the data
function data_init()
{
$.get("param_pozos_linea1.php",
function(data1) {
data_inicial.push([data1]);
callYourPlotFunction(data_inicial);
}
);
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am new to Jquery and ajax.
I need to upload multiple images to server folder and store the details in a db table. After uploading, I need to display all images which set as 'active' in database.( I have looked into many codes which are not working for me)
After that I need to drag some images to an area and also need to store dragged images information in an another table.
Anyone have any idea?Please help me?
Thanks
Nowadays Dropzone.js is the best js plugin to upload multiple images using drag and drop.
official site. https://www.dropzonejs.com/
A complete example of the demo is here.
https://learncodeweb.com/web-development/drag-drop-images-with-bootstrap-4-and-reorder-using-php-jquery-and-ajax/
For uploading multiple images you can use this script. By using single browse button you can upload multiple images
$(function(){
var btnUpload=$('#photo_0'); // id of browse button
new AjaxUpload(btnUpload, {
action: 'url_to_upload_function',
name: 'uploadfile',
onSubmit: function(file, ext){
if (! (ext && /^(jpg|png|jpeg|gif|JPG|PNG|GIF|JPEG)$/.test(ext))){
$("#photo_div1").html('Only JPG,PNG,GIF files are allowed'); //
return false;
}
var path="<?=base_url()?>images/wait.gif"; //losding image
$("#photo_div1").html("<img src="+path+" width='32' height='32' style='border:#b6b6b6 solid 1px;'>");
},
onComplete: function(file, response){
response = jQuery.trim(response);
if(response=="error")
{
$("#photo_error").css("display","block");
$("#upload_photo1").html("");
}
else if(response!="error")
{
$("#photo_error").css("display","none");
$("#photo_div1").html("");
var path="uploads/"+response; //echo the image name from the upload function
var img="<table><tr><td ><img src="+path+" style='border:#b6b6b6 solid 1px;'></td></tr></table>";
$("#img_div1").html(img);// display the image in a div it will display only one image. If you want to add more you can code according to that by using append or something like that
$("#upload_photo1").val(response);
$("#photo_hid1").val(response);
} else
{
alert("error");
}
}
});
});
YOU HAVE TO INCLUDE THIS FILE ALSO ajaxupload.js
/**
* Ajax upload
* Project page - http://valums.com/ajax-upload/
* Copyright (c) 2008 Andris Valums, http://valums.com
* Licensed under the MIT license (http://valums.com/mit-license/)
* Version 3.5 (23.06.2009)
*/
/**
* Changes from the previous version:
* 1. Added better JSON handling that allows to use 'application/javascript' as a response
* 2. Added demo for usage with jQuery UI dialog
* 3. Fixed IE "mixed content" issue when used with secure connections
*
* For the full changelog please visit:
* http://valums.com/ajax-upload-changelog/
*/
(function(){
var d = document, w = window;
/**
* Get element by id
*/
function get(element){
if (typeof element == "string")
element = d.getElementById(element);
return element;
}
/**
* Attaches event to a dom element
*/
function addEvent(el, type, fn){
if (w.addEventListener){
el.addEventListener(type, fn, false);
} else if (w.attachEvent){
var f = function(){
fn.call(el, w.event);
};
el.attachEvent('on' + type, f)
}
}
/**
* Creates and returns element from html chunk
*/
var toElement = function(){
var div = d.createElement('div');
return function(html){
div.innerHTML = html;
var el = div.childNodes[0];
div.removeChild(el);
return el;
}
}();
function hasClass(ele,cls){
return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
// getOffset function copied from jQuery lib (http://jquery.com/)
if (document.documentElement["getBoundingClientRect"]){
// Get Offset using getBoundingClientRect
// http://ejohn.org/blog/getboundingclientrect-is-awesome/
var getOffset = function(el){
var box = el.getBoundingClientRect(),
doc = el.ownerDocument,
body = doc.body,
docElem = doc.documentElement,
// for ie
clientTop = docElem.clientTop || body.clientTop || 0,
clientLeft = docElem.clientLeft || body.clientLeft || 0,
// In Internet Explorer 7 getBoundingClientRect property is treated as physical,
// while others are logical. Make all logical, like in IE8.
zoom = 1;
if (body.getBoundingClientRect) {
var bound = body.getBoundingClientRect();
zoom = (bound.right - bound.left)/body.clientWidth;
}
if (zoom > 1){
clientTop = 0;
clientLeft = 0;
}
var top = box.top/zoom + (window.pageYOffset || docElem && docElem.scrollTop/zoom || body.scrollTop/zoom) - clientTop,
left = box.left/zoom + (window.pageXOffset|| docElem && docElem.scrollLeft/zoom || body.scrollLeft/zoom) - clientLeft;
return {
top: top,
left: left
};
}
} else {
// Get offset adding all offsets
var getOffset = function(el){
if (w.jQuery){
return jQuery(el).offset();
}
var top = 0, left = 0;
do {
top += el.offsetTop || 0;
left += el.offsetLeft || 0;
}
while (el = el.offsetParent);
return {
left: left,
top: top
};
}
}
function getBox(el){
var left, right, top, bottom;
var offset = getOffset(el);
left = offset.left;
top = offset.top;
right = left + el.offsetWidth;
bottom = top + el.offsetHeight;
return {
left: left,
right: right,
top: top,
bottom: bottom
};
}
/**
* Crossbrowser mouse coordinates
*/
function getMouseCoords(e){
// pageX/Y is not supported in IE
// http://www.quirksmode.org/dom/w3c_cssom.html
if (!e.pageX && e.clientX){
// In Internet Explorer 7 some properties (mouse coordinates) are treated as physical,
// while others are logical (offset).
var zoom = 1;
var body = document.body;
if (body.getBoundingClientRect) {
var bound = body.getBoundingClientRect();
zoom = (bound.right - bound.left)/body.clientWidth;
}
return {
x: e.clientX / zoom + d.body.scrollLeft + d.documentElement.scrollLeft,
y: e.clientY / zoom + d.body.scrollTop + d.documentElement.scrollTop
};
}
return {
x: e.pageX,
y: e.pageY
};
}
/**
* Function generates unique id
*/
var getUID = function(){
var id = 0;
return function(){
return 'ValumsAjaxUpload' + id++;
}
}();
function fileFromPath(file){
return file.replace(/.*(\/|\\)/, "");
}
function getExt(file){
return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
}
// Please use AjaxUpload , Ajax_upload will be removed in the next version
Ajax_upload = AjaxUpload = function(button, options){
if (button.jquery){
// jquery object was passed
button = button[0];
} else if (typeof button == "string" && /^#.*/.test(button)){
button = button.slice(1);
}
button = get(button);
this._input = null;
this._button = button;
this._disabled = false;
this._submitting = false;
// Variable changes to true if the button was clicked
// 3 seconds ago (requred to fix Safari on Mac error)
this._justClicked = false;
this._parentDialog = d.body;
if (window.jQuery && jQuery.ui && jQuery.ui.dialog){
var parentDialog = jQuery(this._button).parents('.ui-dialog');
if (parentDialog.length){
this._parentDialog = parentDialog[0];
}
}
this._settings = {
// Location of the server-side upload script
action: 'upload.php',
// File upload name
name: 'userfile',
// Additional data to send
data: {},
// Submit file as soon as it's selected
autoSubmit: true,
// The type of data that you're expecting back from the server.
// Html and xml are detected automatically.
// Only useful when you are using json data as a response.
// Set to "json" in that case.
responseType: false,
// When user selects a file, useful with autoSubmit disabled
onChange: function(file, extension){},
// Callback to fire before file is uploaded
// You can return false to cancel upload
onSubmit: function(file, extension){},
// Fired when file upload is completed
// WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!
onComplete: function(file, response) {}
};
// Merge the users options with our defaults
for (var i in options) {
this._settings[i] = options[i];
}
this._createInput();
this._rerouteClicks();
}
// assigning methods to our class
AjaxUpload.prototype = {
setData : function(data){
this._settings.data = data;
},
disable : function(){
this._disabled = true;
},
enable : function(){
this._disabled = false;
},
// removes ajaxupload
destroy : function(){
if(this._input){
if(this._input.parentNode){
this._input.parentNode.removeChild(this._input);
}
this._input = null;
}
},
/**
* Creates invisible file input above the button
*/
_createInput : function(){
var self = this;
var input = d.createElement("input");
input.setAttribute('type', 'file');
input.setAttribute('name', this._settings.name);
var styles = {
'position' : 'absolute'
,'margin': '-5px 0 0 -175px'
,'padding': 0
,'width': '220px'
,'height': '30px'
,'fontSize': '14px'
,'opacity': 0
,'cursor': 'pointer'
,'display' : 'none'
,'zIndex' : 2147483583 //Max zIndex supported by Opera 9.0-9.2x
// Strange, I expected 2147483647
};
for (var i in styles){
input.style[i] = styles[i];
}
// Make sure that element opacity exists
// (IE uses filter instead)
if ( ! (input.style.opacity === "0")){
input.style.filter = "alpha(opacity=0)";
}
this._parentDialog.appendChild(input);
addEvent(input, 'change', function(){
// get filename from input
var file = fileFromPath(this.value);
if(self._settings.onChange.call(self, file, getExt(file)) == false ){
return;
}
// Submit form when value is changed
if (self._settings.autoSubmit){
self.submit();
}
});
// Fixing problem with Safari
// The problem is that if you leave input before the file select dialog opens
// it does not upload the file.
// As dialog opens slowly (it is a sheet dialog which takes some time to open)
// there is some time while you can leave the button.
// So we should not change display to none immediately
addEvent(input, 'click', function(){
self.justClicked = true;
setTimeout(function(){
// we will wait 3 seconds for dialog to open
self.justClicked = false;
}, 3000);
});
this._input = input;
},
_rerouteClicks : function (){
var self = this;
// IE displays 'access denied' error when using this method
// other browsers just ignore click()
// addEvent(this._button, 'click', function(e){
// self._input.click();
// });
var box, dialogOffset = {top:0, left:0}, over = false;
addEvent(self._button, 'mouseover', function(e){
if (!self._input || over) return;
over = true;
box = getBox(self._button);
if (self._parentDialog != d.body){
dialogOffset = getOffset(self._parentDialog);
}
});
// we can't use mouseout on the button,
// because invisible input is over it
addEvent(document, 'mousemove', function(e){
var input = self._input;
if (!input || !over) return;
if (self._disabled){
removeClass(self._button, 'hover');
input.style.display = 'none';
return;
}
var c = getMouseCoords(e);
if ((c.x >= box.left) && (c.x <= box.right) &&
(c.y >= box.top) && (c.y <= box.bottom)){
input.style.top = c.y - dialogOffset.top + 'px';
input.style.left = c.x - dialogOffset.left + 'px';
input.style.display = 'block';
addClass(self._button, 'hover');
} else {
// mouse left the button
over = false;
if (!self.justClicked){
input.style.display = 'none';
}
removeClass(self._button, 'hover');
}
});
},
/**
* Creates iframe with unique name
*/
_createIframe : function(){
// unique name
// We cannot use getTime, because it sometimes return
// same value in safari :(
var id = getUID();
// Remove ie6 "This page contains both secure and nonsecure items" prompt
// http://tinyurl.com/77w9wh
var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />');
iframe.id = id;
iframe.style.display = 'none';
d.body.appendChild(iframe);
return iframe;
},
/**
* Upload file without refreshing the page
*/
submit : function(){
var self = this, settings = this._settings;
if (this._input.value === ''){
// there is no file
return;
}
// get filename from input
var file = fileFromPath(this._input.value);
// execute user event
if (! (settings.onSubmit.call(this, file, getExt(file)) == false)) {
// Create new iframe for this submission
var iframe = this._createIframe();
// Do not submit if user function returns false
var form = this._createForm(iframe);
form.appendChild(this._input);
form.submit();
d.body.removeChild(form);
form = null;
this._input = null;
// create new input
this._createInput();
var toDeleteFlag = false;
addEvent(iframe, 'load', function(e){
if (// For Safari
iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" ||
// For FF, IE
iframe.src == "javascript:'<html></html>';"){
// First time around, do not delete.
if( toDeleteFlag ){
// Fix busy state in FF3
setTimeout( function() {
d.body.removeChild(iframe);
}, 0);
}
return;
}
var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;
// fixing Opera 9.26
if (doc.readyState && doc.readyState != 'complete'){
// Opera fires load event multiple times
// Even when the DOM is not ready yet
// this fix should not affect other browsers
return;
}
// fixing Opera 9.64
if (doc.body && doc.body.innerHTML == "false"){
// In Opera 9.64 event was fired second time
// when body.innerHTML changed from false
// to server response approx. after 1 sec
return;
}
var response;
if (doc.XMLDocument){
// response is a xml document IE property
response = doc.XMLDocument;
} else if (doc.body){
// response is html document or plain text
response = doc.body.innerHTML;
if (settings.responseType && settings.responseType.toLowerCase() == 'json'){
// If the document was sent as 'application/javascript' or
// 'text/javascript', then the browser wraps the text in a <pre>
// tag and performs html encoding on the contents. In this case,
// we need to pull the original text content from the text node's
// nodeValue property to retrieve the unmangled content.
// Note that IE6 only understands text/html
if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE'){
response = doc.body.firstChild.firstChild.nodeValue;
}
if (response) {
response = window["eval"]("(" + response + ")");
} else {
response = {};
}
}
} else {
// response is a xml document
var response = doc;
}
settings.onComplete.call(self, file, response);
// Reload blank page, so that reloading main page
// does not re-submit the post. Also, remember to
// delete the frame
toDeleteFlag = true;
// Fix IE mixed content issue
iframe.src = "javascript:'<html></html>';";
});
} else {
// clear input to allow user to select same file
// Doesn't work in IE6
// this._input.value = '';
d.body.removeChild(this._input);
this._input = null;
// create new input
this._createInput();
}
},
/**
* Creates form, that will be submitted to iframe
*/
_createForm : function(iframe){
var settings = this._settings;
// method, enctype must be specified here
// because changing this attr on the fly is not allowed in IE 6/7
var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
form.style.display = 'none';
form.action = settings.action;
form.target = iframe.name;
d.body.appendChild(form);
// Create hidden input element for each data key
for (var prop in settings.data){
var el = d.createElement("input");
el.type = 'hidden';
el.name = prop;
el.value = settings.data[prop];
form.appendChild(el);
}
return form;
}
};
})();
and for drag and drop you need to write another function for that you can refer this site or this
http://www.plupload.com/example_queuewidget.php
Here you can find a nice plugin that will help you to upload multiple images.I have used this and works well for me.