1st commit
This commit is contained in:
606
admin/js/jquery.ajaxupload.js
Normal file
606
admin/js/jquery.ajaxupload.js
Normal file
@@ -0,0 +1,606 @@
|
||||
/**
|
||||
* 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/)
|
||||
*/
|
||||
(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()) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross-browser way to get xhr object
|
||||
*/
|
||||
var getXhr = function(){
|
||||
var xhr;
|
||||
|
||||
return function(){
|
||||
if (xhr) return xhr;
|
||||
|
||||
if (typeof XMLHttpRequest !== 'undefined') {
|
||||
xhr = new XMLHttpRequest();
|
||||
} else {
|
||||
var v = [
|
||||
"Microsoft.XmlHttp",
|
||||
"MSXML2.XmlHttp.5.0",
|
||||
"MSXML2.XmlHttp.4.0",
|
||||
"MSXML2.XmlHttp.3.0",
|
||||
"MSXML2.XmlHttp.2.0"
|
||||
];
|
||||
|
||||
for (var i=0; i < v.length; i++){
|
||||
try {
|
||||
xhr = new ActiveXObject(v[i]);
|
||||
break;
|
||||
} catch (e){}
|
||||
}
|
||||
}
|
||||
|
||||
return xhr;
|
||||
}
|
||||
}();
|
||||
|
||||
// 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,
|
||||
// Location of the server-side script that fixes Safari
|
||||
// hanging problem returning "Connection: close" header
|
||||
closeConnection: '',
|
||||
// Class applied to button when mouse is hovered
|
||||
hoverClass: 'hover',
|
||||
// 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 instance
|
||||
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
|
||||
// Doesn't work in IE :(
|
||||
//,'direction' : 'ltr'
|
||||
};
|
||||
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;
|
||||
}, 2500);
|
||||
});
|
||||
|
||||
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, self._settings.hoverClass);
|
||||
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, self._settings.hoverClass);
|
||||
|
||||
} else {
|
||||
// mouse left the button
|
||||
over = false;
|
||||
|
||||
var check = setInterval(function(){
|
||||
// if input was just clicked do not hide it
|
||||
// to prevent safari bug
|
||||
|
||||
if (self.justClicked){
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !over ){
|
||||
input.style.display = 'none';
|
||||
}
|
||||
|
||||
clearInterval(check);
|
||||
|
||||
}, 25);
|
||||
|
||||
|
||||
removeClass(self._button, self._settings.hoverClass);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
/**
|
||||
* Creates iframe with unique name
|
||||
*/
|
||||
_createIframe : function(){
|
||||
// unique name
|
||||
// We cannot use getTime, because it somelustrel 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);
|
||||
|
||||
// A pretty little hack to make uploads not hang in Safari. Just call this
|
||||
// immediately before the upload is submitted. This does an Ajax call to
|
||||
// the server, which returns an empty document with the "Connection: close"
|
||||
// header, telling Safari to close the active connection.
|
||||
// http://blog.airbladesoftware.com/2007/8/17/note-to-self-prevent-uploads-hanging-in-safari
|
||||
if (settings.closeConnection && /AppleWebKit|MSIE/.test(navigator.userAgent)){
|
||||
var xhr = getXhr();
|
||||
// Open synhronous connection
|
||||
xhr.open('GET', settings.closeConnection, false);
|
||||
xhr.send('');
|
||||
}
|
||||
|
||||
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 lustrel
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user