* fixed Issue 157: Upload area tagging file names with 'undefined' and refusing to upload.
* updated plupload to 1.5.1.1 git-svn-id: http://redmine-dmsf.googlecode.com/svn/trunk/redmine_dmsf@248 5e329b0b-a2ee-ea63-e329-299493fc886d
This commit is contained in:
parent
2e862ae750
commit
a52382ad8b
33
assets/javascripts/plupload/i18n/fi.js
Normal file
33
assets/javascripts/plupload/i18n/fi.js
Normal file
@ -0,0 +1,33 @@
|
||||
// .fi file like language pack
|
||||
plupload.addI18n({
|
||||
'Select files' : 'Valitse tiedostoja',
|
||||
'Add files to the upload queue and click the start button.' : 'Lisää tiedostoja latausjonoon ja klikkaa aloita-nappia.',
|
||||
'Filename' : 'Tiedostonimi',
|
||||
'Status' : 'Tila',
|
||||
'Size' : 'Koko',
|
||||
'Add files' : 'Lisää tiedostoja',
|
||||
'Stop current upload' : 'Pysäytä nykyinen lataus',
|
||||
'Start uploading queue' : 'Aloita jonon lataus',
|
||||
'Drag files here.' : 'Raahaa tiedostot tänne.',
|
||||
'Start upload' : 'Aloita lataus',
|
||||
'Uploaded %d/%d files': 'Ladattu %d/%d tiedostoa',
|
||||
'Stop upload': 'Pysäytä lataus',
|
||||
'Start upload': 'Aloita lataus',
|
||||
'%d files queued': '%d tiedostoa jonossa',
|
||||
'File: %s': 'Tiedosto: %s',
|
||||
'Close': 'Sulje',
|
||||
'Using runtime: ': 'Käytetään ajonaikaista: ',
|
||||
'File: %f, size: %s, max file size: %m': 'Tiedosto: %f, koko: %s, maksimi tiedostokoko: %m',
|
||||
'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Latauselementti sallii ladata vain %d tiedosto(a) kerrallaan. Ylimääräiset tiedostot ohitettiin.',
|
||||
'Upload URL might be wrong or doesn\'t exist': 'Lataus URL saattaa olla väärin tai ei ole olemassa',
|
||||
'Error: File too large: ': 'Virhe: Tiedosto liian suuri: ',
|
||||
'Error: Invalid file extension: ': 'Virhe: Kelpaamaton tiedostopääte: ',
|
||||
'File extension error.': 'Tiedostopäätevirhe.',
|
||||
'File size error.': 'Tiedostokokovirhe.',
|
||||
'File count error.': 'Tiedostolaskentavirhe.',
|
||||
'Init error.': 'Init virhe.',
|
||||
'HTTP Error.': 'HTTP virhe.',
|
||||
'Security error.': 'Tietoturvavirhe.',
|
||||
'Generic error.': 'Yleinen virhe.',
|
||||
'IO error.': 'I/O virhe.'
|
||||
});
|
||||
@ -1,25 +1,37 @@
|
||||
// Japanese
|
||||
plupload.addI18n({
|
||||
'Select files' : 'ファイルの選択:',
|
||||
'Add files to the upload queue and click the start button.' : 'アップロードキューにファイルを追加しスタートボタンをクリックしてください。',
|
||||
'Filename' : 'ファイル名',
|
||||
'Status' : '進行状況',
|
||||
'Size' : 'サイズ',
|
||||
'Add files' : 'ファイルの追加',
|
||||
'Stop current upload' : '現在のアップロードを中止',
|
||||
'Start uploading queue' : 'キューのアップロードを開始',
|
||||
'Uploaded %d/%d files': '%d/%d 個のファイルをアップロードしました',
|
||||
'N/A' : 'N/A',
|
||||
'Drag files here.' : 'ここにファイルをドラッグしてください。',
|
||||
'File extension error.': 'ファイル拡張子エラーです。',
|
||||
'File size error.': 'ファイルサイズエラーです。',
|
||||
'Init error.': '初期化エラーです。',
|
||||
'HTTP Error.': 'HTTP エラーです。',
|
||||
'Security error.': 'セキュリティエラーです。',
|
||||
'Generic error.': '原因不明のエラーです。',
|
||||
'IO error.': 'I/O エラーです。',
|
||||
'Stop Upload': 'アップロードの中止',
|
||||
'Add Files': 'ファイルの追加',
|
||||
'Start Upload': 'アップロードの開始',
|
||||
'%d files queued': '%d 個のファイルがキューにあります。'
|
||||
});
|
||||
// Japanese
|
||||
plupload.addI18n({
|
||||
'Select files' : 'ファイル選択',
|
||||
'Add files to the upload queue and click the start button.' : 'ファイルをアップロードキューに追加してスタートボタンをクリックしてください',
|
||||
'Filename' : 'ファイル名',
|
||||
'Status' : 'ステータス',
|
||||
'Size' : 'サイズ',
|
||||
'Add Files' : 'ファイルを追加',
|
||||
'Stop Upload' : 'アップロード停止',
|
||||
'Start Upload' : 'アップロード',
|
||||
'Add files' : 'ファイルを追加',
|
||||
'Add files.' : 'ファイルを追加',
|
||||
'Stop current upload' : '現在のアップロードを停止',
|
||||
'Start uploading queue' : 'アップロード',
|
||||
'Stop upload' : 'アップロード停止',
|
||||
'Start upload' : 'アップロード',
|
||||
'Uploaded %d/%d files': 'アップロード中 %d/%d ファイル',
|
||||
'N/A' : 'N/A',
|
||||
'Drag files here.' : 'ここにファイルをドラッグ',
|
||||
'File extension error.': 'ファイル拡張子エラー',
|
||||
'File size error.': 'ファイルサイズエラー',
|
||||
'File count error.': 'ファイル数エラー',
|
||||
'Init error.': 'イニシャライズエラー',
|
||||
'HTTP Error.': 'HTTP エラー',
|
||||
'Security error.': 'セキュリティエラー',
|
||||
'Generic error.': 'エラー',
|
||||
'IO error.': 'IO エラー',
|
||||
'File: %s': 'ファイル: %s',
|
||||
'Close': '閉じる',
|
||||
'%d files queued': '%d ファイルが追加されました',
|
||||
'Using runtime: ': 'モード: ',
|
||||
'File: %f, size: %s, max file size: %m': 'ファイル: %f, サイズ: %s, 最大ファイルサイズ: %m',
|
||||
'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'アップロード可能なファイル数は %d です。余分なファイルは削除されました',
|
||||
'Upload URL might be wrong or doesn\'t exist': 'アップロード先の URL が存在しません',
|
||||
'Error: File too large: ': 'エラー: サイズが大きすぎます: ',
|
||||
'Error: Invalid file extension: ': 'エラー: 拡張子が許可されていません: '
|
||||
});
|
||||
|
||||
@ -20,7 +20,7 @@ plupload.addI18n({
|
||||
'File: %f, size: %s, max file size: %m': 'Fails: %f, izmērs: %s, maksimālais faila izmērs: %m',
|
||||
'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Iespējams ielādēt tikai %d failus vienā reizē. Atlikušie faili netika pievienoti',
|
||||
'Upload URL might be wrong or doesn\'t exist': 'Augšupielādes URL varētu būt nepareizs vai neeksistē',
|
||||
'Error: File to large: ': 'Kļūda: Fails pārāk liels: ',
|
||||
'Error: File too large: ': 'Kļūda: Fails pārāk liels: ',
|
||||
'Error: Invalid file extension: ': 'Kļūda: Nekorekts faila paplašinājums:',
|
||||
'File extension error.': 'Faila paplašinājuma kļūda.',
|
||||
'File size error.': 'Faila izmēra kļūda.',
|
||||
|
||||
@ -30,6 +30,6 @@ plupload.addI18n({
|
||||
'File: %f, size: %s, max file size: %m': 'Arquivo: %f, tamanho: %s, máximo: %m',
|
||||
'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Só são aceitos %d arquivos por vez. O que passou disso foi descartado.',
|
||||
'Upload URL might be wrong or doesn\'t exist': 'URL de envio está errada ou não existe',
|
||||
'Error: File to large: ': 'Erro: Arquivo muito grande: ',
|
||||
'Error: File too large: ': 'Erro: Arquivo muito grande: ',
|
||||
'Error: Invalid file extension: ': 'Erro: Tipo de arquivo não permitido: '
|
||||
});
|
||||
|
||||
@ -37,7 +37,7 @@ function renderUI(obj) {
|
||||
'<div class="plupload_header_content">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
||||
|
||||
'<div class="plupload_content">' +
|
||||
'<table class="plupload_filelist">' +
|
||||
'<tr class="ui-widget-header plupload_filelist_header">' +
|
||||
@ -133,7 +133,11 @@ $.widget("ui.plupload", {
|
||||
this.container = $('.plupload_container', this.element).attr('id', id + '_container');
|
||||
|
||||
// list of files, may become sortable
|
||||
this.filelist = $('.plupload_filelist_content', this.container).attr('id', id + '_filelist');
|
||||
this.filelist = $('.plupload_filelist_content', this.container)
|
||||
.attr({
|
||||
id: id + '_filelist',
|
||||
unselectable: 'on'
|
||||
});
|
||||
|
||||
// buttons
|
||||
this.browse_button = $('.plupload_add', this.container).attr('id', id + '_browse');
|
||||
@ -217,12 +221,12 @@ $.widget("ui.plupload", {
|
||||
|
||||
// check if file count doesn't exceed the limit
|
||||
if (self.options.max_file_count) {
|
||||
uploader.bind('FilesAdded', function(up, files) {
|
||||
var length = files.length, removed = [];
|
||||
length += up.files.length;
|
||||
uploader.bind('FilesAdded', function(up, selectedFiles) {
|
||||
var removed = [], selectedCount = selectedFiles.length;
|
||||
var extraCount = up.files.length + selectedCount - self.options.max_file_count;
|
||||
|
||||
if (length > self.options.max_file_count) {
|
||||
removed = files.splice(self.options.max_file_count - up.files.length);
|
||||
if (extraCount > 0) {
|
||||
removed = selectedFiles.splice(selectedCount - extraCount, extraCount);
|
||||
|
||||
up.trigger('Error', {
|
||||
code : self.FILE_COUNT_ERROR,
|
||||
@ -336,7 +340,7 @@ $.widget("ui.plupload", {
|
||||
message += " <br /><i>" + details + "</i>";
|
||||
}
|
||||
|
||||
self._notify('error', message);
|
||||
self.notify('error', message);
|
||||
self._trigger('error', null, { up: up, file: file, error: message } );
|
||||
}
|
||||
});
|
||||
@ -651,24 +655,12 @@ $.widget("ui.plupload", {
|
||||
return el.clone(true).find('td:not(.plupload_file_name)').remove().end().css('width', '100%');
|
||||
},
|
||||
|
||||
start: function(e, ui) {
|
||||
idxStart = $('tr', this).index(ui.item);
|
||||
},
|
||||
|
||||
stop: function(e, ui) {
|
||||
var i, length, idx, files = [], idxStop = $('tr', this).index(ui.item);
|
||||
|
||||
for (i = 0, length = self.uploader.files.length; i < length; i++) {
|
||||
|
||||
if (i === idxStop) {
|
||||
idx = idxStart;
|
||||
} else if (i === idxStart) {
|
||||
idx = idxStop;
|
||||
} else {
|
||||
idx = i;
|
||||
}
|
||||
files[files.length] = self.uploader.files[idx];
|
||||
}
|
||||
var i, length, idx, files = [];
|
||||
|
||||
$.each($(this).sortable('toArray'), function(i, id) {
|
||||
files[files.length] = self.uploader.getFile(id);
|
||||
});
|
||||
|
||||
files.unshift(files.length);
|
||||
files.unshift(0);
|
||||
@ -679,7 +671,7 @@ $.widget("ui.plupload", {
|
||||
});
|
||||
},
|
||||
|
||||
_notify: function(type, message) {
|
||||
notify: function(type, message) {
|
||||
var popup = $(
|
||||
'<div class="plupload_message">' +
|
||||
'<span class="plupload_message_close ui-icon ui-icon-circle-close" title="'+_('Close')+'"></span>' +
|
||||
@ -696,8 +688,9 @@ $.widget("ui.plupload", {
|
||||
.click(function() {
|
||||
popup.remove();
|
||||
})
|
||||
.end()
|
||||
.appendTo('.plupload_header_content', this.container);
|
||||
.end();
|
||||
|
||||
$('.plupload_header_content', this.container).append(popup);
|
||||
},
|
||||
|
||||
|
||||
|
||||
@ -1,337 +0,0 @@
|
||||
/**
|
||||
* plupload.browserplus.js
|
||||
*
|
||||
* Copyright 2009, Moxiecode Systems AB
|
||||
* Released under GPL License.
|
||||
*
|
||||
* License: http://www.plupload.com/license
|
||||
* Contributing: http://www.plupload.com/contributing
|
||||
*/
|
||||
|
||||
// JSLint defined globals
|
||||
/*global plupload:false, BrowserPlus:false, window:false */
|
||||
|
||||
(function(plupload) {
|
||||
/**
|
||||
* Yahoo BrowserPlus implementation. This runtime supports these features: dragdrop, jpgresize, pngresize.
|
||||
*
|
||||
* @static
|
||||
* @class plupload.runtimes.BrowserPlus
|
||||
* @extends plupload.Runtime
|
||||
*/
|
||||
plupload.runtimes.BrowserPlus = plupload.addRuntime("browserplus", {
|
||||
/**
|
||||
* Returns a list of supported features for the runtime.
|
||||
*
|
||||
* @return {Object} Name/value object with supported features.
|
||||
*/
|
||||
getFeatures : function() {
|
||||
return {
|
||||
dragdrop : true,
|
||||
jpgresize : true,
|
||||
pngresize : true,
|
||||
chunks : true,
|
||||
progress: true,
|
||||
multipart: true
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the browserplus runtime.
|
||||
*
|
||||
* @method init
|
||||
* @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
|
||||
* @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
|
||||
*/
|
||||
init : function(uploader, callback) {
|
||||
var browserPlus = window.BrowserPlus, browserPlusFiles = {}, settings = uploader.settings, resize = settings.resize;
|
||||
|
||||
function addSelectedFiles(native_files) {
|
||||
var files, i, selectedFiles = [], file, id;
|
||||
|
||||
// Add the native files and setup plupload files
|
||||
for (i = 0; i < native_files.length; i++) {
|
||||
file = native_files[i];
|
||||
id = plupload.guid();
|
||||
browserPlusFiles[id] = file;
|
||||
|
||||
selectedFiles.push(new plupload.File(id, file.name, file.size));
|
||||
}
|
||||
|
||||
// Any files selected fire event
|
||||
if (i) {
|
||||
uploader.trigger("FilesAdded", selectedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup event listeners if browserplus was initialized
|
||||
function setup() {
|
||||
// Add drop handler
|
||||
uploader.bind("PostInit", function() {
|
||||
var dropTargetElm, dropElmId = settings.drop_element,
|
||||
dropTargetId = uploader.id + '_droptarget',
|
||||
dropElm = document.getElementById(dropElmId),
|
||||
lastState;
|
||||
|
||||
// Enable/disable drop support for the drop target
|
||||
// this is needed to resolve IE bubbeling issues and make it possible to drag/drop
|
||||
// files into gears runtimes on the same page
|
||||
function addDropHandler(id, end_callback) {
|
||||
// Add drop target and listener
|
||||
browserPlus.DragAndDrop.AddDropTarget({id : id}, function(res) {
|
||||
browserPlus.DragAndDrop.AttachCallbacks({
|
||||
id : id,
|
||||
hover : function(res) {
|
||||
if (!res && end_callback) {
|
||||
end_callback();
|
||||
}
|
||||
},
|
||||
drop : function(res) {
|
||||
if (end_callback) {
|
||||
end_callback();
|
||||
}
|
||||
|
||||
addSelectedFiles(res);
|
||||
}
|
||||
}, function() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function hide() {
|
||||
document.getElementById(dropTargetId).style.top = '-1000px';
|
||||
}
|
||||
|
||||
if (dropElm) {
|
||||
// Since IE has issues with bubbeling when it comes to the drop of files
|
||||
// we need to do this hack where we show a drop target div element while dropping
|
||||
if (document.attachEvent && (/MSIE/gi).test(navigator.userAgent)) {
|
||||
// Create drop target
|
||||
dropTargetElm = document.createElement('div');
|
||||
dropTargetElm.setAttribute('id', dropTargetId);
|
||||
plupload.extend(dropTargetElm.style, {
|
||||
position : 'absolute',
|
||||
top : '-1000px',
|
||||
background : 'red',
|
||||
filter : 'alpha(opacity=0)',
|
||||
opacity : 0
|
||||
});
|
||||
|
||||
document.body.appendChild(dropTargetElm);
|
||||
|
||||
plupload.addEvent(dropElm, 'dragenter', function(e) {
|
||||
var dropElm, dropElmPos;
|
||||
|
||||
dropElm = document.getElementById(dropElmId);
|
||||
dropElmPos = plupload.getPos(dropElm);
|
||||
|
||||
plupload.extend(document.getElementById(dropTargetId).style, {
|
||||
top : dropElmPos.y + 'px',
|
||||
left : dropElmPos.x + 'px',
|
||||
width : dropElm.offsetWidth + 'px',
|
||||
height : dropElm.offsetHeight + 'px'
|
||||
});
|
||||
});
|
||||
|
||||
addDropHandler(dropTargetId, hide);
|
||||
} else {
|
||||
addDropHandler(dropElmId);
|
||||
}
|
||||
}
|
||||
|
||||
plupload.addEvent(document.getElementById(settings.browse_button), 'click', function(e) {
|
||||
var mimeTypes = [], i, a, filters = settings.filters, ext;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// Convert extensions to mimetypes
|
||||
for (i = 0; i < filters.length; i++) {
|
||||
ext = filters[i].extensions.split(',');
|
||||
|
||||
for (a = 0; a < ext.length; a++) {
|
||||
mimeTypes.push(plupload.mimeTypes[ext[a]]);
|
||||
}
|
||||
}
|
||||
|
||||
browserPlus.FileBrowse.OpenBrowseDialog({
|
||||
mimeTypes : mimeTypes
|
||||
}, function(res) {
|
||||
if (res.success) {
|
||||
addSelectedFiles(res.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Prevent IE leaks
|
||||
dropElm = dropTargetElm = null;
|
||||
});
|
||||
|
||||
uploader.bind("UploadFile", function(up, file) {
|
||||
var nativeFile = browserPlusFiles[file.id], reqParams = {},
|
||||
chunkSize = up.settings.chunk_size, loadProgress, chunkStack = [];
|
||||
|
||||
function uploadFile(chunk, chunks) {
|
||||
var chunkFile;
|
||||
|
||||
// Stop upload if file is maked as failed
|
||||
if (file.status == plupload.FAILED) {
|
||||
return;
|
||||
}
|
||||
|
||||
reqParams.name = file.target_name || file.name;
|
||||
|
||||
// Only send chunk parameters if chunk size is defined
|
||||
if (chunkSize) {
|
||||
reqParams.chunk = "" + chunk;
|
||||
reqParams.chunks = "" + chunks;
|
||||
}
|
||||
|
||||
chunkFile = chunkStack.shift();
|
||||
|
||||
browserPlus.Uploader.upload({
|
||||
url : up.settings.url,
|
||||
files : {file : chunkFile},
|
||||
cookies : document.cookies,
|
||||
postvars : plupload.extend(reqParams, up.settings.multipart_params),
|
||||
progressCallback : function(res) {
|
||||
var i, loaded = 0;
|
||||
|
||||
// since more than 1 chunk can be sent at a time, keep track of how many bytes
|
||||
// of each chunk was sent
|
||||
loadProgress[chunk] = parseInt(res.filePercent * chunkFile.size / 100, 10);
|
||||
for (i = 0; i < loadProgress.length; i++) {
|
||||
loaded += loadProgress[i];
|
||||
}
|
||||
|
||||
file.loaded = loaded;
|
||||
up.trigger('UploadProgress', file);
|
||||
}
|
||||
}, function(res) {
|
||||
var httpStatus, chunkArgs;
|
||||
|
||||
if (res.success) {
|
||||
httpStatus = res.value.statusCode;
|
||||
|
||||
if (chunkSize) {
|
||||
up.trigger('ChunkUploaded', file, {
|
||||
chunk : chunk,
|
||||
chunks : chunks,
|
||||
response : res.value.body,
|
||||
status : httpStatus
|
||||
});
|
||||
}
|
||||
|
||||
if (chunkStack.length > 0) {
|
||||
// More chunks to be uploaded
|
||||
uploadFile(++chunk, chunks);
|
||||
} else {
|
||||
file.status = plupload.DONE;
|
||||
|
||||
up.trigger('FileUploaded', file, {
|
||||
response : res.value.body,
|
||||
status : httpStatus
|
||||
});
|
||||
|
||||
// Is error status
|
||||
if (httpStatus >= 400) {
|
||||
up.trigger('Error', {
|
||||
code : plupload.HTTP_ERROR,
|
||||
message : plupload.translate('HTTP Error.'),
|
||||
file : file,
|
||||
status : httpStatus
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
up.trigger('Error', {
|
||||
code : plupload.GENERIC_ERROR,
|
||||
message : plupload.translate('Generic Error.'),
|
||||
file : file,
|
||||
details : res.error
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function chunkAndUploadFile(native_file) {
|
||||
file.size = native_file.size;
|
||||
if (chunkSize) {
|
||||
browserPlus.FileAccess.chunk({file : native_file, chunkSize : chunkSize}, function(cr) {
|
||||
if (cr.success) {
|
||||
var chunks = cr.value, len = chunks.length;
|
||||
|
||||
loadProgress = Array(len);
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
loadProgress[i] = 0;
|
||||
chunkStack.push(chunks[i]);
|
||||
}
|
||||
|
||||
uploadFile(0, len);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
loadProgress = Array(1);
|
||||
chunkStack.push(native_file);
|
||||
uploadFile(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Resize image if it's a supported format and resize is enabled
|
||||
if (resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
|
||||
BrowserPlus.ImageAlter.transform({
|
||||
file : nativeFile,
|
||||
quality : resize.quality || 90,
|
||||
actions : [{
|
||||
scale : {
|
||||
maxwidth : resize.width,
|
||||
maxheight : resize.height
|
||||
}
|
||||
}]
|
||||
}, function(res) {
|
||||
if (res.success) {
|
||||
chunkAndUploadFile(res.value.file);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
chunkAndUploadFile(nativeFile);
|
||||
}
|
||||
});
|
||||
|
||||
callback({success : true});
|
||||
}
|
||||
|
||||
// Check for browserplus object
|
||||
if (browserPlus) {
|
||||
browserPlus.init(function(res) {
|
||||
var services = [
|
||||
{service: "Uploader", version: "3"},
|
||||
{service: "DragAndDrop", version: "1"},
|
||||
{service: "FileBrowse", version: "1"},
|
||||
{service: "FileAccess", version: "2"}
|
||||
];
|
||||
|
||||
if (resize) {
|
||||
services.push({service : 'ImageAlter', version : "4"});
|
||||
}
|
||||
|
||||
if (res.success) {
|
||||
browserPlus.require({
|
||||
services : services
|
||||
}, function(sres) {
|
||||
if (sres.success) {
|
||||
setup();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
})(plupload);
|
||||
@ -42,7 +42,7 @@
|
||||
* @param {Object} obj Parameters to be passed with event.
|
||||
*/
|
||||
trigger : function(id, name, obj) {
|
||||
|
||||
|
||||
// Detach the call so that error handling in the browser is presented correctly
|
||||
setTimeout(function() {
|
||||
var uploader = uploadInstances[id], i, args;
|
||||
@ -76,7 +76,8 @@
|
||||
maxHeight: 8091,
|
||||
chunks: true,
|
||||
progress: true,
|
||||
multipart: true
|
||||
multipart: true,
|
||||
multi_selection: true
|
||||
};
|
||||
},
|
||||
|
||||
@ -88,12 +89,7 @@
|
||||
* @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
|
||||
*/
|
||||
init : function(uploader, callback) {
|
||||
var browseButton, flashContainer, flashVars, waitCount = 0, container = document.body;
|
||||
|
||||
if (bowser.opera) {
|
||||
callback({success : false});
|
||||
return;
|
||||
}
|
||||
var browseButton, flashContainer, waitCount = 0, container = document.body;
|
||||
|
||||
if (getFlashVersion() < 10) {
|
||||
callback({success : false});
|
||||
@ -129,15 +125,33 @@
|
||||
}
|
||||
|
||||
container.appendChild(flashContainer);
|
||||
|
||||
// insert flash object
|
||||
(function() {
|
||||
var html, el;
|
||||
|
||||
html = '<object id="' + uploader.id + '_flash" type="application/x-shockwave-flash" data="' + uploader.settings.flash_swf_url + '" ';
|
||||
|
||||
if (plupload.ua.ie) {
|
||||
html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '
|
||||
}
|
||||
|
||||
flashVars = 'id=' + escape(uploader.id);
|
||||
|
||||
// Insert the Flash inide the flash container
|
||||
flashContainer.innerHTML = '<object id="' + uploader.id + '_flash" width="100%" height="100%" style="outline:0" type="application/x-shockwave-flash" data="' + uploader.settings.flash_swf_url + '">' +
|
||||
'<param name="movie" value="' + uploader.settings.flash_swf_url + '" />' +
|
||||
'<param name="flashvars" value="' + flashVars + '" />' +
|
||||
'<param name="wmode" value="transparent" />' +
|
||||
'<param name="allowscriptaccess" value="always" /></object>';
|
||||
html += 'width="100%" height="100%" style="outline:0">' +
|
||||
'<param name="movie" value="' + uploader.settings.flash_swf_url + '" />' +
|
||||
'<param name="flashvars" value="id=' + escape(uploader.id) + '" />' +
|
||||
'<param name="wmode" value="transparent" />' +
|
||||
'<param name="allowscriptaccess" value="always" />' +
|
||||
'</object>';
|
||||
|
||||
if (plupload.ua.ie) {
|
||||
el = document.createElement('div');
|
||||
flashContainer.appendChild(el);
|
||||
el.outerHTML = html;
|
||||
el = null; // just in case
|
||||
} else {
|
||||
flashContainer.innerHTML = html;
|
||||
}
|
||||
}());
|
||||
|
||||
function getFlashObj() {
|
||||
return document.getElementById(uploader.id + '_flash');
|
||||
@ -334,6 +348,17 @@
|
||||
plupload.removeClass(browseButton, activeClass);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
uploader.bind('Flash:ExifData', function(up, obj) {
|
||||
uploader.trigger('ExifData', uploader.getFile(lookup[obj.id]), obj.data);
|
||||
});
|
||||
|
||||
|
||||
uploader.bind('Flash:GpsData', function(up, obj) {
|
||||
uploader.trigger('GpsData', uploader.getFile(lookup[obj.id]), obj.data);
|
||||
});
|
||||
|
||||
|
||||
uploader.bind("QueueChanged", function(up) {
|
||||
uploader.refresh();
|
||||
|
||||
Binary file not shown.
@ -1,420 +0,0 @@
|
||||
/**
|
||||
* plupload.gears.js
|
||||
*
|
||||
* Copyright 2009, Moxiecode Systems AB
|
||||
* Released under GPL License.
|
||||
*
|
||||
* License: http://www.plupload.com/license
|
||||
* Contributing: http://www.plupload.com/contributing
|
||||
*/
|
||||
|
||||
// JSLint defined globals
|
||||
/*global window:false, document:false, plupload:false, google:false, GearsFactory:false, ActiveXObject:false */
|
||||
|
||||
// Copyright 2007, Google Inc.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// 3. Neither the name of Google Inc. nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Sets up google.gears.*, which is *the only* supported way to access Gears.
|
||||
//
|
||||
// Circumvent this file at your own risk!
|
||||
//
|
||||
// In the future, Gears may automatically define google.gears.* without this
|
||||
// file. Gears may use these objects to transparently fix bugs and compatibility
|
||||
// issues. Applications that use the code below will continue to work seamlessly
|
||||
// when that happens.
|
||||
|
||||
(function() {
|
||||
// We are already defined. Hooray!
|
||||
if (window.google && google.gears) {
|
||||
return;
|
||||
}
|
||||
|
||||
var factory = null;
|
||||
|
||||
// Firefox
|
||||
if (typeof GearsFactory != 'undefined') {
|
||||
factory = new GearsFactory();
|
||||
} else {
|
||||
// IE
|
||||
try {
|
||||
factory = new ActiveXObject('Gears.Factory');
|
||||
// privateSetGlobalObject is only required and supported on WinCE.
|
||||
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
|
||||
factory.privateSetGlobalObject(this);
|
||||
}
|
||||
} catch (e) {
|
||||
// Safari
|
||||
if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
|
||||
factory = document.createElement("object");
|
||||
factory.style.display = "none";
|
||||
factory.width = 0;
|
||||
factory.height = 0;
|
||||
factory.type = "application/x-googlegears";
|
||||
document.documentElement.appendChild(factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *Do not* define any objects if Gears is not installed. This mimics the
|
||||
// behavior of Gears defining the objects in the future.
|
||||
if (!factory) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now set up the objects, being careful not to overwrite anything.
|
||||
//
|
||||
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
|
||||
// the window object. However, global objects are automatically added as
|
||||
// properties of the window object in all browsers.
|
||||
if (!window.google) {
|
||||
window.google = {};
|
||||
}
|
||||
|
||||
if (!google.gears) {
|
||||
google.gears = {factory: factory};
|
||||
}
|
||||
})();
|
||||
|
||||
(function(window, document, plupload, undef) {
|
||||
var blobs = {};
|
||||
|
||||
function scaleImage(image_blob, resize, mime) {
|
||||
var percentage, canvas, context, scale;
|
||||
|
||||
// Setup canvas and scale
|
||||
canvas = google.gears.factory.create('beta.canvas');
|
||||
try {
|
||||
canvas.decode(image_blob);
|
||||
|
||||
if (!resize['width']) {
|
||||
resize['width'] = canvas.width;
|
||||
}
|
||||
|
||||
if (!resize['height']) {
|
||||
resize['height'] = canvas.height;
|
||||
}
|
||||
|
||||
scale = Math.min(width / canvas.width, height / canvas.height);
|
||||
|
||||
if (scale < 1 || (scale === 1 && mime === 'image/jpeg')) {
|
||||
canvas.resize(Math.round(canvas.width * scale), Math.round(canvas.height * scale));
|
||||
|
||||
if (resize['quality']) {
|
||||
return canvas.encode(mime, {quality : resize.quality / 100});
|
||||
}
|
||||
|
||||
return canvas.encode(mime);
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore for example when a user uploads a file that can't be decoded
|
||||
}
|
||||
|
||||
return image_blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gears implementation. This runtime supports these features: dragdrop, jpgresize, pngresize, chunks.
|
||||
*
|
||||
* @static
|
||||
* @class plupload.runtimes.Gears
|
||||
* @extends plupload.Runtime
|
||||
*/
|
||||
plupload.runtimes.Gears = plupload.addRuntime("gears", {
|
||||
/**
|
||||
* Returns a list of supported features for the runtime.
|
||||
*
|
||||
* @return {Object} Name/value object with supported features.
|
||||
*/
|
||||
getFeatures : function() {
|
||||
return {
|
||||
dragdrop: true,
|
||||
jpgresize: true,
|
||||
pngresize: true,
|
||||
chunks: true,
|
||||
progress: true,
|
||||
multipart: true
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the upload runtime.
|
||||
*
|
||||
* @method init
|
||||
* @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
|
||||
* @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
|
||||
*/
|
||||
init : function(uploader, callback) {
|
||||
var desktop;
|
||||
|
||||
// Check for gears support
|
||||
if (!window.google || !google.gears) {
|
||||
return callback({success : false});
|
||||
}
|
||||
|
||||
try {
|
||||
desktop = google.gears.factory.create('beta.desktop');
|
||||
} catch (e) {
|
||||
// Might fail on the latest Gecko build for some odd reason
|
||||
return callback({success : false});
|
||||
}
|
||||
|
||||
function addSelectedFiles(selected_files) {
|
||||
var file, i, files = [], id;
|
||||
|
||||
// Add the selected files to the file queue
|
||||
for (i = 0; i < selected_files.length; i++) {
|
||||
file = selected_files[i];
|
||||
|
||||
// Store away gears blob internally
|
||||
id = plupload.guid();
|
||||
blobs[id] = file.blob;
|
||||
|
||||
files.push(new plupload.File(id, file.name, file.blob.length));
|
||||
}
|
||||
|
||||
// Fire FilesAdded event
|
||||
uploader.trigger("FilesAdded", files);
|
||||
}
|
||||
|
||||
// Add drop handler
|
||||
uploader.bind("PostInit", function() {
|
||||
var settings = uploader.settings, dropElm = document.getElementById(settings.drop_element);
|
||||
|
||||
if (dropElm) {
|
||||
// Block browser default drag over
|
||||
plupload.addEvent(dropElm, 'dragover', function(e) {
|
||||
desktop.setDropEffect(e, 'copy');
|
||||
e.preventDefault();
|
||||
}, uploader.id);
|
||||
|
||||
// Attach drop handler and grab files from Gears
|
||||
plupload.addEvent(dropElm, 'drop', function(e) {
|
||||
var dragData = desktop.getDragData(e, 'application/x-gears-files');
|
||||
|
||||
if (dragData) {
|
||||
addSelectedFiles(dragData.files);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
}, uploader.id);
|
||||
|
||||
// Prevent IE leak
|
||||
dropElm = 0;
|
||||
}
|
||||
|
||||
// Add browse button
|
||||
plupload.addEvent(document.getElementById(settings.browse_button), 'click', function(e) {
|
||||
var filters = [], i, a, ext;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
for (i = 0; i < settings.filters.length; i++) {
|
||||
ext = settings.filters[i].extensions.split(',');
|
||||
|
||||
for (a = 0; a < ext.length; a++) {
|
||||
filters.push('.' + ext[a]);
|
||||
}
|
||||
}
|
||||
|
||||
desktop.openFiles(addSelectedFiles, {singleFile : !settings.multi_selection, filter : filters});
|
||||
}, uploader.id);
|
||||
});
|
||||
|
||||
uploader.bind("UploadFile", function(up, file) {
|
||||
var chunk = 0, chunks, chunkSize, loaded = 0, resize = up.settings.resize, chunking;
|
||||
|
||||
// If file is png or jpeg and resize is configured then resize it
|
||||
if (resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
|
||||
blobs[file.id] = scaleImage(blobs[file.id], resize, /\.png$/i.test(file.name) ? 'image/png' : 'image/jpeg');
|
||||
}
|
||||
|
||||
file.size = blobs[file.id].length;
|
||||
|
||||
chunkSize = up.settings.chunk_size;
|
||||
chunking = chunkSize > 0;
|
||||
chunks = Math.ceil(file.size / chunkSize);
|
||||
|
||||
// If chunking is disabled then upload the whole file in one huge chunk
|
||||
if (!chunking) {
|
||||
chunkSize = file.size;
|
||||
chunks = 1;
|
||||
}
|
||||
|
||||
function uploadNextChunk() {
|
||||
var req, curChunkSize, multipart = up.settings.multipart, multipartLength = 0, reqArgs = {name : file.target_name || file.name}, url = up.settings.url;
|
||||
|
||||
// Sends the binary blob multipart encoded or raw depending on config
|
||||
function sendBinaryBlob(blob) {
|
||||
var builder, boundary = '----pluploadboundary' + plupload.guid(), dashdash = '--', crlf = '\r\n', multipartBlob, mimeType;
|
||||
|
||||
// Build multipart request
|
||||
if (multipart) {
|
||||
req.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
|
||||
builder = google.gears.factory.create('beta.blobbuilder');
|
||||
|
||||
// Append mutlipart parameters
|
||||
plupload.each(plupload.extend(reqArgs, up.settings.multipart_params), function(value, name) {
|
||||
builder.append(
|
||||
dashdash + boundary + crlf +
|
||||
'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf
|
||||
);
|
||||
|
||||
builder.append(value + crlf);
|
||||
});
|
||||
|
||||
mimeType = plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream';
|
||||
|
||||
// Add file header
|
||||
builder.append(
|
||||
dashdash + boundary + crlf +
|
||||
'Content-Disposition: form-data; name="' + up.settings.file_data_name + '"; filename="' + file.name + '"' + crlf +
|
||||
'Content-Type: ' + mimeType + crlf + crlf
|
||||
);
|
||||
|
||||
// Add file data
|
||||
builder.append(blob);
|
||||
|
||||
// Add footer
|
||||
builder.append(crlf + dashdash + boundary + dashdash + crlf);
|
||||
multipartBlob = builder.getAsBlob();
|
||||
multipartLength = multipartBlob.length - blob.length;
|
||||
blob = multipartBlob;
|
||||
}
|
||||
|
||||
// Send blob or multipart blob depending on config
|
||||
req.send(blob);
|
||||
}
|
||||
|
||||
// File upload finished
|
||||
if (file.status == plupload.DONE || file.status == plupload.FAILED || up.state == plupload.STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only add chunking args if needed
|
||||
if (chunking) {
|
||||
reqArgs.chunk = chunk;
|
||||
reqArgs.chunks = chunks;
|
||||
}
|
||||
|
||||
// Setup current chunk size
|
||||
curChunkSize = Math.min(chunkSize, file.size - (chunk * chunkSize));
|
||||
|
||||
if (!multipart) {
|
||||
url = plupload.buildUrl(up.settings.url, reqArgs);
|
||||
}
|
||||
|
||||
req = google.gears.factory.create('beta.httprequest');
|
||||
req.open('POST', url);
|
||||
|
||||
// Add disposition and type if multipart is disabled
|
||||
if (!multipart) {
|
||||
req.setRequestHeader('Content-Disposition', 'attachment; filename="' + file.name + '"');
|
||||
req.setRequestHeader('Content-Type', 'application/octet-stream');
|
||||
}
|
||||
|
||||
// Set custom headers
|
||||
plupload.each(up.settings.headers, function(value, name) {
|
||||
req.setRequestHeader(name, value);
|
||||
});
|
||||
|
||||
req.upload.onprogress = function(progress) {
|
||||
file.loaded = loaded + progress.loaded - multipartLength;
|
||||
up.trigger('UploadProgress', file);
|
||||
};
|
||||
|
||||
req.onreadystatechange = function() {
|
||||
var chunkArgs;
|
||||
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
chunkArgs = {
|
||||
chunk : chunk,
|
||||
chunks : chunks,
|
||||
response : req.responseText,
|
||||
status : req.status
|
||||
};
|
||||
|
||||
up.trigger('ChunkUploaded', file, chunkArgs);
|
||||
|
||||
// Stop upload
|
||||
if (chunkArgs.cancelled) {
|
||||
file.status = plupload.FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
loaded += curChunkSize;
|
||||
|
||||
if (++chunk >= chunks) {
|
||||
file.status = plupload.DONE;
|
||||
up.trigger('FileUploaded', file, {
|
||||
response : req.responseText,
|
||||
status : req.status
|
||||
});
|
||||
} else {
|
||||
uploadNextChunk();
|
||||
}
|
||||
} else {
|
||||
up.trigger('Error', {
|
||||
code : plupload.HTTP_ERROR,
|
||||
message : plupload.translate('HTTP Error.'),
|
||||
file : file,
|
||||
chunk : chunk,
|
||||
chunks : chunks,
|
||||
status : req.status
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (chunk < chunks) {
|
||||
sendBinaryBlob(blobs[file.id].slice(chunk * chunkSize, curChunkSize));
|
||||
}
|
||||
}
|
||||
|
||||
// Start uploading chunks
|
||||
uploadNextChunk();
|
||||
});
|
||||
|
||||
uploader.bind("Destroy", function(up) {
|
||||
var name, element,
|
||||
elements = {
|
||||
browseButton: up.settings.browse_button,
|
||||
dropElm: up.settings.drop_element
|
||||
};
|
||||
|
||||
// Unbind event handlers
|
||||
for (name in elements) {
|
||||
element = document.getElementById(elements[name]);
|
||||
if (element) {
|
||||
plupload.removeAllEvents(element, up.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
callback({success : true});
|
||||
}
|
||||
});
|
||||
})(window, document, plupload);
|
||||
@ -30,15 +30,13 @@
|
||||
*
|
||||
* @return {Object} Name/value object with supported features.
|
||||
*/
|
||||
getFeatures : function() {
|
||||
getFeatures : function() {
|
||||
// Only multipart feature
|
||||
return {
|
||||
multipart: true,
|
||||
|
||||
/* WebKit let you trigger file dialog programmatically while FF and Opera - do not, so we
|
||||
sniff for it here... probably not that good idea, but impossibillity of controlling cursor style
|
||||
on top of add files button obviously feels even worse */
|
||||
canOpenDialog: navigator.userAgent.indexOf('WebKit') !== -1
|
||||
// WebKit and Gecko 2+ can trigger file dialog progrmmatically
|
||||
triggerDialog: (plupload.ua.gecko && window.FormData || plupload.ua.webkit)
|
||||
};
|
||||
},
|
||||
|
||||
@ -106,7 +104,7 @@
|
||||
browseButton = getById(up.settings.browse_button);
|
||||
|
||||
// Route click event to input element programmatically, if possible
|
||||
if (up.features.canOpenDialog && browseButton) {
|
||||
if (up.features.triggerDialog && browseButton) {
|
||||
plupload.addEvent(getById(up.settings.browse_button), 'click', function(e) {
|
||||
input.click();
|
||||
e.preventDefault();
|
||||
@ -118,7 +116,7 @@
|
||||
width : '100%',
|
||||
height : '100%',
|
||||
opacity : 0,
|
||||
fontSize: '99px' // force input element to be bigger then needed to occupy whole space
|
||||
fontSize: '999px' // force input element to be bigger then needed to occupy whole space
|
||||
});
|
||||
|
||||
plupload.extend(form.style, {
|
||||
@ -153,7 +151,7 @@
|
||||
files.push(new plupload.File(currentFileId, name));
|
||||
|
||||
// Clean-up events - they won't be needed anymore
|
||||
if (!up.features.canOpenDialog) {
|
||||
if (!up.features.triggerDialog) {
|
||||
plupload.removeAllEvents(form, up.id);
|
||||
} else {
|
||||
plupload.removeEvent(browseButton, 'click', up.id);
|
||||
@ -209,8 +207,8 @@
|
||||
}
|
||||
|
||||
// Get result
|
||||
result = el.documentElement.innerText || el.documentElement.textContent;
|
||||
|
||||
result = el.body.innerHTML;
|
||||
|
||||
// Assume no error
|
||||
if (result) {
|
||||
currentFile.status = plupload.DONE;
|
||||
@ -287,14 +285,16 @@
|
||||
if (up.state == plupload.STOPPED) {
|
||||
window.setTimeout(function() {
|
||||
plupload.removeEvent(iframe, 'load', up.id);
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
if (iframe.parentNode) { // #382
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh button, will reposition the input form
|
||||
up.bind("Refresh", function(up) {
|
||||
var browseButton, topElement, hoverClass, activeClass, browsePos, browseSize, inputContainer, inputFile, pzIndex;
|
||||
var browseButton, topElement, hoverClass, activeClass, browsePos, browseSize, inputContainer, inputFile, zIndex;
|
||||
|
||||
browseButton = getById(up.settings.browse_button);
|
||||
if (browseButton) {
|
||||
@ -312,25 +312,25 @@
|
||||
|
||||
// for IE and WebKit place input element underneath the browse button and route onclick event
|
||||
// TODO: revise when browser support for this feature will change
|
||||
if (up.features.canOpenDialog) {
|
||||
pzIndex = parseInt(browseButton.parentNode.style.zIndex, 10);
|
||||
|
||||
if (isNaN(pzIndex)) {
|
||||
pzIndex = 0;
|
||||
}
|
||||
|
||||
plupload.extend(browseButton.style, {
|
||||
zIndex : pzIndex
|
||||
});
|
||||
|
||||
if (up.features.triggerDialog) {
|
||||
if (plupload.getStyle(browseButton, 'position') === 'static') {
|
||||
plupload.extend(browseButton.style, {
|
||||
position : 'relative'
|
||||
});
|
||||
}
|
||||
|
||||
zIndex = parseInt(browseButton.style.zIndex, 10);
|
||||
|
||||
if (isNaN(zIndex)) {
|
||||
zIndex = 0;
|
||||
}
|
||||
|
||||
plupload.extend(browseButton.style, {
|
||||
zIndex : zIndex
|
||||
});
|
||||
|
||||
plupload.extend(inputContainer.style, {
|
||||
zIndex : pzIndex - 1
|
||||
zIndex : zIndex - 1
|
||||
});
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@
|
||||
TODO: needs to be revised as things will change */
|
||||
hoverClass = up.settings.browse_button_hover;
|
||||
activeClass = up.settings.browse_button_active;
|
||||
topElement = up.features.canOpenDialog ? browseButton : inputContainer;
|
||||
topElement = up.features.triggerDialog ? browseButton : inputContainer;
|
||||
|
||||
if (hoverClass) {
|
||||
plupload.addEvent(topElement, 'mouseover', function() {
|
||||
|
||||
@ -12,27 +12,8 @@
|
||||
/*global plupload:false, File:false, window:false, atob:false, FormData:false, FileReader:false, ArrayBuffer:false, Uint8Array:false, BlobBuilder:false, unescape:false */
|
||||
|
||||
(function(window, document, plupload, undef) {
|
||||
var fakeSafariDragDrop;
|
||||
|
||||
if ((typeof File !== 'undefined') && !File.prototype.slice) {
|
||||
if (File.prototype.webkitSlice) File.prototype.slice = File.prototype.webkitSlice;
|
||||
if (File.prototype.mozSlice) File.prototype.slice = File.prototype.mozSlice;
|
||||
}
|
||||
|
||||
/* Introduce sendAsBinary for latest WebKits having support for BlobBuilder and typed arrays:
|
||||
credits: http://javascript0.org/wiki/Portable_sendAsBinary,
|
||||
more info: http://code.google.com/p/chromium/issues/detail?id=35705
|
||||
*/
|
||||
if (window.Uint8Array && window.ArrayBuffer && !XMLHttpRequest.prototype.sendAsBinary) {
|
||||
XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
|
||||
var ui8a = new Uint8Array(datastr.length);
|
||||
for (var i = 0; i < datastr.length; i++) {
|
||||
ui8a[i] = (datastr.charCodeAt(i) & 0xff);
|
||||
}
|
||||
this.send(ui8a.buffer);
|
||||
};
|
||||
}
|
||||
|
||||
var html5files = {}, // queue of original File objects
|
||||
fakeSafariDragDrop;
|
||||
|
||||
function readFileAsDataURL(file, callback) {
|
||||
var reader;
|
||||
@ -64,10 +45,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
function scaleImage(image_file, resize, mime, callback) {
|
||||
var canvas, context, img, scale;
|
||||
|
||||
readFileAsDataURL(image_file, function(data) {
|
||||
function scaleImage(file, resize, mime, callback) {
|
||||
var canvas, context, img, scale,
|
||||
up = this;
|
||||
|
||||
readFileAsDataURL(html5files[file.id], function(data) {
|
||||
// Setup canvas and context
|
||||
canvas = document.createElement("canvas");
|
||||
canvas.style.display = 'none';
|
||||
@ -112,9 +94,18 @@
|
||||
// Set new width and height
|
||||
exifParser.setExif('PixelXDimension', width);
|
||||
exifParser.setExif('PixelYDimension', height);
|
||||
|
||||
|
||||
// Update EXIF header
|
||||
jpegHeaders.set('exif', exifParser.getBinary());
|
||||
|
||||
// trigger Exif events only if someone listens to them
|
||||
if (up.hasEventListener('ExifData')) {
|
||||
up.trigger('ExifData', file, exifParser.EXIF());
|
||||
}
|
||||
|
||||
if (up.hasEventListener('GpsData')) {
|
||||
up.trigger('GpsData', file, exifParser.GPS());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,8 +125,8 @@
|
||||
data = data.substring(data.indexOf('base64,') + 7);
|
||||
data = atob(data);
|
||||
|
||||
// Restore JPEG headers
|
||||
if (jpegHeaders['headers'] && jpegHeaders['headers'].length) {
|
||||
// Restore JPEG headers if applicable
|
||||
if (jpegHeaders && jpegHeaders['headers'] && jpegHeaders['headers'].length) {
|
||||
data = jpegHeaders.restore(data);
|
||||
jpegHeaders.purge(); // free memory
|
||||
}
|
||||
@ -167,11 +158,11 @@
|
||||
* @return {Object} Name/value object with supported features.
|
||||
*/
|
||||
getFeatures : function() {
|
||||
var xhr, hasXhrSupport, hasProgress, dataAccessSupport, sliceSupport, win = window;
|
||||
var xhr, hasXhrSupport, hasProgress, canSendBinary, dataAccessSupport, sliceSupport;
|
||||
|
||||
hasXhrSupport = hasProgress = dataAccessSupport = sliceSupport = false;
|
||||
|
||||
if (win.XMLHttpRequest) {
|
||||
if (window.XMLHttpRequest) {
|
||||
xhr = new XMLHttpRequest();
|
||||
hasProgress = !!xhr.upload;
|
||||
hasXhrSupport = !!(xhr.sendAsBinary || xhr.upload);
|
||||
@ -179,28 +170,35 @@
|
||||
|
||||
// Check for support for various features
|
||||
if (hasXhrSupport) {
|
||||
canSendBinary = !!(xhr.sendAsBinary || (window.Uint8Array && window.ArrayBuffer));
|
||||
|
||||
// Set dataAccessSupport only for Gecko since BlobBuilder and XHR doesn't handle binary data correctly
|
||||
dataAccessSupport = !!(File && (File.prototype.getAsDataURL || win.FileReader) && xhr.sendAsBinary);
|
||||
sliceSupport = !!(File && File.prototype.slice);
|
||||
dataAccessSupport = !!(File && (File.prototype.getAsDataURL || window.FileReader) && canSendBinary);
|
||||
sliceSupport = !!(File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice));
|
||||
}
|
||||
|
||||
// Sniff for Safari and fake drag/drop
|
||||
fakeSafariDragDrop = navigator.userAgent.indexOf('Safari') > 0 && navigator.vendor.indexOf('Apple') !== -1;
|
||||
// sniff out Safari for Windows and fake drag/drop
|
||||
fakeSafariDragDrop = plupload.ua.safari && plupload.ua.windows;
|
||||
|
||||
return {
|
||||
// Detect drag/drop file support by sniffing, will try to find a better way
|
||||
html5: hasXhrSupport, // This is a special one that we check inside the init call
|
||||
dragdrop: win.mozInnerScreenX !== undef || sliceSupport || fakeSafariDragDrop,
|
||||
dragdrop: (function() {
|
||||
// this comes directly from Modernizr: http://www.modernizr.com/
|
||||
var div = document.createElement('div');
|
||||
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
|
||||
}()),
|
||||
jpgresize: dataAccessSupport,
|
||||
pngresize: dataAccessSupport,
|
||||
multipart: dataAccessSupport || !!win.FileReader || !!win.FormData,
|
||||
multipart: dataAccessSupport || !!window.FileReader || !!window.FormData,
|
||||
canSendBinary: canSendBinary,
|
||||
// gecko 2/5/6 can't send blob with FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
|
||||
cantSendBlobInFormData: !!(plupload.ua.gecko && window.FormData && window.FileReader && !FileReader.prototype.readAsArrayBuffer),
|
||||
progress: hasProgress,
|
||||
chunks: sliceSupport || dataAccessSupport,
|
||||
|
||||
/* WebKit let you trigger file dialog programmatically while FF and Opera - do not, so we
|
||||
sniff for it here... probably not that good idea, but impossibillity of controlling cursor style
|
||||
on top of add files button obviously feels even worse */
|
||||
canOpenDialog: navigator.userAgent.indexOf('WebKit') !== -1
|
||||
chunks: sliceSupport,
|
||||
// Safari on Windows has problems when selecting multiple files
|
||||
multi_selection: !(plupload.ua.safari && plupload.ua.windows),
|
||||
// WebKit and Gecko 2+ can trigger file dialog progrmmatically
|
||||
triggerDialog: (plupload.ua.gecko && window.FormData || plupload.ua.webkit)
|
||||
};
|
||||
},
|
||||
|
||||
@ -212,7 +210,7 @@
|
||||
* @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
|
||||
*/
|
||||
init : function(uploader, callback) {
|
||||
var html5files = {}, features;
|
||||
var features;
|
||||
|
||||
function addSelectedFiles(native_files) {
|
||||
var file, i, files = [], id, fileNames = {};
|
||||
@ -220,7 +218,7 @@
|
||||
// Add the selected files to the file queue
|
||||
for (i = 0; i < native_files.length; i++) {
|
||||
file = native_files[i];
|
||||
|
||||
|
||||
// Safari on Windows will add first file from dragged set multiple times
|
||||
// @see: https://bugs.webkit.org/show_bug.cgi?id=37957
|
||||
if (fileNames[file.name]) {
|
||||
@ -233,7 +231,7 @@
|
||||
html5files[id] = file;
|
||||
|
||||
// Expose id, name and size
|
||||
files.push(new plupload.File(id, file.fileName, file.fileSize || file.size)); // File.fileSize depricated
|
||||
files.push(new plupload.File(id, file.fileName || file.name, file.fileSize || file.size)); // fileName / fileSize depricated
|
||||
}
|
||||
|
||||
// Trigger FilesAdded event if we added any
|
||||
@ -265,7 +263,6 @@
|
||||
zIndex : 99999,
|
||||
opacity : uploader.settings.shim_bgcolor ? '' : 0 // Force transparent if bgcolor is undefined
|
||||
});
|
||||
|
||||
inputContainer.className = 'plupload html5';
|
||||
|
||||
if (uploader.settings.container) {
|
||||
@ -300,29 +297,44 @@
|
||||
|
||||
|
||||
// Insert the input inside the input container
|
||||
inputContainer.innerHTML = '<input id="' + uploader.id + '_html5" ' +
|
||||
'style="width:100%;height:100%;font-size:99px" type="file" accept="' +
|
||||
mimes.join(',') + '" ' +
|
||||
(uploader.settings.multi_selection ? 'multiple="multiple"' : '') + ' />';
|
||||
|
||||
inputContainer.innerHTML = '<input id="' + uploader.id + '_html5" ' + ' style="font-size:999px"' +
|
||||
' type="file" accept="' + mimes.join(',') + '" ' +
|
||||
(uploader.settings.multi_selection && uploader.features.multi_selection ? 'multiple="multiple"' : '') + ' />';
|
||||
|
||||
inputContainer.scrollTop = 100;
|
||||
inputFile = document.getElementById(uploader.id + '_html5');
|
||||
|
||||
if (up.features.triggerDialog) {
|
||||
plupload.extend(inputFile.style, {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
});
|
||||
} else {
|
||||
// shows arrow cursor instead of the text one, bit more logical
|
||||
plupload.extend(inputFile.style, {
|
||||
cssFloat: 'right',
|
||||
styleFloat: 'right'
|
||||
});
|
||||
}
|
||||
|
||||
inputFile.onchange = function() {
|
||||
// Add the selected files from file input
|
||||
addSelectedFiles(this.files);
|
||||
|
||||
|
||||
// Clearing the value enables the user to select the same file again if they want to
|
||||
this.value = '';
|
||||
};
|
||||
|
||||
/* Since we have to place input[type=file] on top of the browse_button for some browsers (FF, Opera),
|
||||
browse_button loses interactivity, here we try to neutralize this issue highlighting browse_button
|
||||
with a special class
|
||||
with a special classes
|
||||
TODO: needs to be revised as things will change */
|
||||
browseButton = document.getElementById(up.settings.browse_button);
|
||||
if (browseButton) {
|
||||
var hoverClass = up.settings.browse_button_hover,
|
||||
activeClass = up.settings.browse_button_active,
|
||||
topElement = up.features.canOpenDialog ? browseButton : inputContainer;
|
||||
topElement = up.features.triggerDialog ? browseButton : inputContainer;
|
||||
|
||||
if (hoverClass) {
|
||||
plupload.addEvent(topElement, 'mouseover', function() {
|
||||
@ -343,7 +355,7 @@
|
||||
}
|
||||
|
||||
// Route click event to the input[type=file] element for supporting browsers
|
||||
if (up.features.canOpenDialog) {
|
||||
if (up.features.triggerDialog) {
|
||||
plupload.addEvent(browseButton, 'click', function(e) {
|
||||
document.getElementById(up.id + '_html5').click();
|
||||
e.preventDefault();
|
||||
@ -374,7 +386,7 @@
|
||||
plupload.addEvent(dropInputElm, 'change', function() {
|
||||
// Add the selected files from file input
|
||||
addSelectedFiles(this.files);
|
||||
|
||||
|
||||
// Remove input element
|
||||
plupload.removeEvent(dropInputElm, 'change', uploader.id);
|
||||
dropInputElm.parentNode.removeChild(dropInputElm);
|
||||
@ -426,7 +438,7 @@
|
||||
});
|
||||
|
||||
uploader.bind("Refresh", function(up) {
|
||||
var browseButton, browsePos, browseSize, inputContainer, pzIndex;
|
||||
var browseButton, browsePos, browseSize, inputContainer, zIndex;
|
||||
|
||||
browseButton = document.getElementById(uploader.settings.browse_button);
|
||||
if (browseButton) {
|
||||
@ -443,25 +455,24 @@
|
||||
|
||||
// for WebKit place input element underneath the browse button and route onclick event
|
||||
// TODO: revise when browser support for this feature will change
|
||||
if (uploader.features.canOpenDialog) {
|
||||
pzIndex = parseInt(browseButton.parentNode.style.zIndex, 10);
|
||||
|
||||
if (isNaN(pzIndex)) {
|
||||
pzIndex = 0;
|
||||
}
|
||||
|
||||
plupload.extend(browseButton.style, {
|
||||
zIndex : pzIndex
|
||||
});
|
||||
|
||||
if (uploader.features.triggerDialog) {
|
||||
if (plupload.getStyle(browseButton, 'position') === 'static') {
|
||||
plupload.extend(browseButton.style, {
|
||||
position : 'relative'
|
||||
});
|
||||
}
|
||||
|
||||
zIndex = parseInt(plupload.getStyle(browseButton, 'z-index'), 10);
|
||||
if (isNaN(zIndex)) {
|
||||
zIndex = 0;
|
||||
}
|
||||
|
||||
plupload.extend(browseButton.style, {
|
||||
zIndex : zIndex
|
||||
});
|
||||
|
||||
plupload.extend(inputContainer.style, {
|
||||
zIndex : pzIndex - 1
|
||||
zIndex : zIndex - 1
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -469,14 +480,201 @@
|
||||
|
||||
uploader.bind("UploadFile", function(up, file) {
|
||||
var settings = up.settings, nativeFile, resize;
|
||||
|
||||
function w3cBlobSlice(blob, start, end) {
|
||||
var blobSlice;
|
||||
|
||||
if (File.prototype.slice) {
|
||||
try {
|
||||
blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception
|
||||
return blob.slice(start, end);
|
||||
} catch (e) {
|
||||
// depricated slice method
|
||||
return blob.slice(start, end - start);
|
||||
}
|
||||
// slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
|
||||
} else if (blobSlice = File.prototype.webkitSlice || File.prototype.mozSlice) {
|
||||
return blobSlice.call(blob, start, end);
|
||||
} else {
|
||||
return null; // or throw some exception
|
||||
}
|
||||
}
|
||||
|
||||
function sendBinaryBlob(blob) {
|
||||
var chunk = 0, loaded = 0;
|
||||
var chunk = 0, loaded = 0,
|
||||
fr = ("FileReader" in window) ? new FileReader : null;
|
||||
|
||||
|
||||
function uploadNextChunk() {
|
||||
var chunkBlob = blob, xhr, upload, chunks, args, multipartDeltaSize = 0,
|
||||
boundary = '----pluploadboundary' + plupload.guid(), chunkSize, curChunkSize, formData,
|
||||
dashdash = '--', crlf = '\r\n', multipartBlob = '', mimeType, url = up.settings.url;
|
||||
var chunkBlob, br, chunks, args, chunkSize, curChunkSize, mimeType, url = up.settings.url;
|
||||
|
||||
|
||||
function prepareAndSend(bin) {
|
||||
var multipartDeltaSize = 0,
|
||||
xhr = new XMLHttpRequest,
|
||||
upload = xhr.upload,
|
||||
boundary = '----pluploadboundary' + plupload.guid(), formData, dashdash = '--', crlf = '\r\n', multipartBlob = ''
|
||||
|
||||
// Do we have upload progress support
|
||||
if (upload) {
|
||||
upload.onprogress = function(e) {
|
||||
file.loaded = Math.min(file.size, loaded + e.loaded - multipartDeltaSize); // Loaded can be larger than file size due to multipart encoding
|
||||
up.trigger('UploadProgress', file);
|
||||
};
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
var httpStatus, chunkArgs;
|
||||
|
||||
if (xhr.readyState == 4) {
|
||||
// Getting the HTTP status might fail on some Gecko versions
|
||||
try {
|
||||
httpStatus = xhr.status;
|
||||
} catch (ex) {
|
||||
httpStatus = 0;
|
||||
}
|
||||
|
||||
// Is error status
|
||||
if (httpStatus >= 400) {
|
||||
up.trigger('Error', {
|
||||
code : plupload.HTTP_ERROR,
|
||||
message : plupload.translate('HTTP Error.'),
|
||||
file : file,
|
||||
status : httpStatus
|
||||
});
|
||||
} else {
|
||||
// Handle chunk response
|
||||
if (chunks) {
|
||||
chunkArgs = {
|
||||
chunk : chunk,
|
||||
chunks : chunks,
|
||||
response : xhr.responseText,
|
||||
status : httpStatus
|
||||
};
|
||||
|
||||
up.trigger('ChunkUploaded', file, chunkArgs);
|
||||
loaded += curChunkSize;
|
||||
|
||||
// Stop upload
|
||||
if (chunkArgs.cancelled) {
|
||||
file.status = plupload.FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
file.loaded = Math.min(file.size, (chunk + 1) * chunkSize);
|
||||
} else {
|
||||
file.loaded = file.size;
|
||||
}
|
||||
|
||||
up.trigger('UploadProgress', file);
|
||||
|
||||
bin = chunkBlob = formData = multipartBlob = null; // Free memory
|
||||
|
||||
// Check if file is uploaded
|
||||
if (!chunks || ++chunk >= chunks) {
|
||||
file.status = plupload.DONE;
|
||||
|
||||
up.trigger('FileUploaded', file, {
|
||||
response : xhr.responseText,
|
||||
status : httpStatus
|
||||
});
|
||||
} else {
|
||||
// Still chunks left
|
||||
uploadNextChunk();
|
||||
}
|
||||
}
|
||||
|
||||
xhr = null;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Build multipart request
|
||||
if (up.settings.multipart && features.multipart) {
|
||||
|
||||
args.name = file.target_name || file.name;
|
||||
|
||||
xhr.open("post", url, true);
|
||||
|
||||
// Set custom headers
|
||||
plupload.each(up.settings.headers, function(value, name) {
|
||||
xhr.setRequestHeader(name, value);
|
||||
});
|
||||
|
||||
|
||||
// if has FormData support like Chrome 6+, Safari 5+, Firefox 4, use it
|
||||
if (typeof(bin) !== 'string' && !!window.FormData) {
|
||||
formData = new FormData();
|
||||
|
||||
// Add multipart params
|
||||
plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
|
||||
formData.append(name, value);
|
||||
});
|
||||
|
||||
// Add file and send it
|
||||
formData.append(up.settings.file_data_name, bin);
|
||||
xhr.send(formData);
|
||||
|
||||
return;
|
||||
} // if no FormData we can still try to send it directly as last resort (see below)
|
||||
|
||||
|
||||
if (typeof(bin) === 'string') {
|
||||
// Trying to send the whole thing as binary...
|
||||
|
||||
// multipart request
|
||||
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
|
||||
|
||||
// append multipart parameters
|
||||
plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
|
||||
multipartBlob += dashdash + boundary + crlf +
|
||||
'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf;
|
||||
|
||||
multipartBlob += unescape(encodeURIComponent(value)) + crlf;
|
||||
});
|
||||
|
||||
mimeType = plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream';
|
||||
|
||||
// Build RFC2388 blob
|
||||
multipartBlob += dashdash + boundary + crlf +
|
||||
'Content-Disposition: form-data; name="' + up.settings.file_data_name + '"; filename="' + unescape(encodeURIComponent(file.name)) + '"' + crlf +
|
||||
'Content-Type: ' + mimeType + crlf + crlf +
|
||||
bin + crlf +
|
||||
dashdash + boundary + dashdash + crlf;
|
||||
|
||||
multipartDeltaSize = multipartBlob.length - bin.length;
|
||||
bin = multipartBlob;
|
||||
|
||||
|
||||
if (xhr.sendAsBinary) { // Gecko
|
||||
xhr.sendAsBinary(bin);
|
||||
} else if (features.canSendBinary) { // WebKit with typed arrays support
|
||||
var ui8a = new Uint8Array(bin.length);
|
||||
for (var i = 0; i < bin.length; i++) {
|
||||
ui8a[i] = (bin.charCodeAt(i) & 0xff);
|
||||
}
|
||||
xhr.send(ui8a.buffer);
|
||||
}
|
||||
return; // will return from here only if shouldn't send binary
|
||||
}
|
||||
}
|
||||
|
||||
// if no multipart, or last resort, send as binary stream
|
||||
url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params));
|
||||
|
||||
xhr.open("post", url, true);
|
||||
|
||||
xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header
|
||||
|
||||
// Set custom headers
|
||||
plupload.each(up.settings.headers, function(value, name) {
|
||||
xhr.setRequestHeader(name, value);
|
||||
});
|
||||
|
||||
xhr.send(bin);
|
||||
} // prepareAndSend
|
||||
|
||||
|
||||
// File upload finished
|
||||
if (file.status == plupload.DONE || file.status == plupload.FAILED || up.state == plupload.STOPPED) {
|
||||
@ -487,7 +685,7 @@
|
||||
args = {name : file.target_name || file.name};
|
||||
|
||||
// Only add chunking args if needed
|
||||
if (settings.chunk_size && features.chunks) {
|
||||
if (settings.chunk_size && file.size > settings.chunk_size && (features.chunks || typeof(blob) == 'string')) { // blob will be of type string if it was loaded in memory
|
||||
chunkSize = settings.chunk_size;
|
||||
chunks = Math.ceil(file.size / chunkSize);
|
||||
curChunkSize = Math.min(chunkSize, file.size - (chunk * chunkSize));
|
||||
@ -498,7 +696,7 @@
|
||||
chunkBlob = blob.substring(chunk * chunkSize, chunk * chunkSize + curChunkSize);
|
||||
} else {
|
||||
// Slice the chunk
|
||||
chunkBlob = blob.slice(chunk * chunkSize, curChunkSize);
|
||||
chunkBlob = w3cBlobSlice(blob, chunk * chunkSize, chunk * chunkSize + curChunkSize);
|
||||
}
|
||||
|
||||
// Setup query string arguments
|
||||
@ -506,148 +704,19 @@
|
||||
args.chunks = chunks;
|
||||
} else {
|
||||
curChunkSize = file.size;
|
||||
chunkBlob = blob;
|
||||
}
|
||||
|
||||
// Setup XHR object
|
||||
xhr = new XMLHttpRequest();
|
||||
upload = xhr.upload;
|
||||
|
||||
// Do we have upload progress support
|
||||
if (upload) {
|
||||
upload.onprogress = function(e) {
|
||||
file.loaded = Math.min(file.size, loaded + e.loaded - multipartDeltaSize); // Loaded can be larger than file size due to multipart encoding
|
||||
up.trigger('UploadProgress', file);
|
||||
};
|
||||
}
|
||||
|
||||
// Add name, chunk and chunks to query string on direct streaming
|
||||
if (!up.settings.multipart || !features.multipart) {
|
||||
url = plupload.buildUrl(up.settings.url, args);
|
||||
} else {
|
||||
args.name = file.target_name || file.name;
|
||||
}
|
||||
|
||||
xhr.open("post", url, true);
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
var httpStatus, chunkArgs;
|
||||
|
||||
if (xhr.readyState == 4) {
|
||||
// Getting the HTTP status might fail on some Gecko versions
|
||||
try {
|
||||
httpStatus = xhr.status;
|
||||
} catch (ex) {
|
||||
httpStatus = 0;
|
||||
}
|
||||
|
||||
// Is error status
|
||||
if (httpStatus >= 400) {
|
||||
up.trigger('Error', {
|
||||
code : plupload.HTTP_ERROR,
|
||||
message : plupload.translate('HTTP Error.'),
|
||||
file : file,
|
||||
status : httpStatus
|
||||
});
|
||||
} else {
|
||||
// Handle chunk response
|
||||
if (chunks) {
|
||||
chunkArgs = {
|
||||
chunk : chunk,
|
||||
chunks : chunks,
|
||||
response : xhr.responseText,
|
||||
status : httpStatus
|
||||
};
|
||||
|
||||
up.trigger('ChunkUploaded', file, chunkArgs);
|
||||
loaded += curChunkSize;
|
||||
|
||||
// Stop upload
|
||||
if (chunkArgs.cancelled) {
|
||||
file.status = plupload.FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
file.loaded = Math.min(file.size, (chunk + 1) * chunkSize);
|
||||
} else {
|
||||
file.loaded = file.size;
|
||||
}
|
||||
|
||||
up.trigger('UploadProgress', file);
|
||||
|
||||
// Check if file is uploaded
|
||||
if (!chunks || ++chunk >= chunks) {
|
||||
file.status = plupload.DONE;
|
||||
up.trigger('FileUploaded', file, {
|
||||
response : xhr.responseText,
|
||||
status : httpStatus
|
||||
});
|
||||
|
||||
nativeFile = blob = html5files[file.id] = null; // Free memory
|
||||
} else {
|
||||
// Still chunks left
|
||||
uploadNextChunk();
|
||||
}
|
||||
}
|
||||
|
||||
xhr = chunkBlob = formData = multipartBlob = null; // Free memory
|
||||
|
||||
// workaround Gecko 2,5,6 FormData+Blob bug: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
|
||||
if (typeof(chunkBlob) !== 'string' && fr && features.cantSendBlobInFormData && features.chunks && up.settings.chunk_size) {// Gecko 2,5,6
|
||||
fr.onload = function() {
|
||||
prepareAndSend(fr.result);
|
||||
}
|
||||
};
|
||||
|
||||
// Set custom headers
|
||||
plupload.each(up.settings.headers, function(value, name) {
|
||||
xhr.setRequestHeader(name, value);
|
||||
});
|
||||
|
||||
// Build multipart request
|
||||
if (up.settings.multipart && features.multipart) {
|
||||
// Has FormData support like Chrome 6+, Safari 5+, Firefox 4
|
||||
if (!xhr.sendAsBinary) {
|
||||
formData = new FormData();
|
||||
|
||||
// Add multipart params
|
||||
plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
|
||||
formData.append(name, value);
|
||||
});
|
||||
|
||||
// Add file and send it
|
||||
formData.append(up.settings.file_data_name, chunkBlob);
|
||||
xhr.send(formData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Gecko multipart request
|
||||
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
|
||||
|
||||
// Append multipart parameters
|
||||
plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
|
||||
multipartBlob += dashdash + boundary + crlf +
|
||||
'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf;
|
||||
|
||||
multipartBlob += unescape(encodeURIComponent(value)) + crlf;
|
||||
});
|
||||
|
||||
mimeType = plupload.mimeTypes[file.name.replace(/^.+\.([^.]+)/, '$1').toLowerCase()] || 'application/octet-stream';
|
||||
|
||||
// Build RFC2388 blob
|
||||
multipartBlob += dashdash + boundary + crlf +
|
||||
'Content-Disposition: form-data; name="' + up.settings.file_data_name + '"; filename="' + unescape(encodeURIComponent(file.name)) + '"' + crlf +
|
||||
'Content-Type: ' + mimeType + crlf + crlf +
|
||||
chunkBlob + crlf +
|
||||
dashdash + boundary + dashdash + crlf;
|
||||
|
||||
multipartDeltaSize = multipartBlob.length - chunkBlob.length;
|
||||
chunkBlob = multipartBlob;
|
||||
fr.readAsBinaryString(chunkBlob);
|
||||
} else {
|
||||
// Binary stream header
|
||||
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
|
||||
}
|
||||
|
||||
if (xhr.sendAsBinary) {
|
||||
xhr.sendAsBinary(chunkBlob); // Gecko
|
||||
} else {
|
||||
xhr.send(chunkBlob); // WebKit
|
||||
prepareAndSend(chunkBlob);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Start uploading chunks
|
||||
@ -655,26 +724,24 @@
|
||||
}
|
||||
|
||||
nativeFile = html5files[file.id];
|
||||
resize = up.settings.resize;
|
||||
|
||||
if (features.jpgresize) {
|
||||
// Resize image if it's a supported format and resize is enabled
|
||||
if (resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
|
||||
scaleImage(nativeFile, resize, /\.png$/i.test(file.name) ? 'image/png' : 'image/jpeg', function(res) {
|
||||
// If it was scaled send the scaled image if it failed then
|
||||
// send the raw image and let the server do the scaling
|
||||
if (res.success) {
|
||||
file.size = res.data.length;
|
||||
sendBinaryBlob(res.data);
|
||||
} else {
|
||||
readFileAsBinary(nativeFile, sendBinaryBlob);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
readFileAsBinary(nativeFile, sendBinaryBlob);
|
||||
}
|
||||
|
||||
// Resize image if it's a supported format and resize is enabled
|
||||
if (features.jpgresize && up.settings.resize && /\.(png|jpg|jpeg)$/i.test(file.name)) {
|
||||
scaleImage.call(up, file, up.settings.resize, /\.png$/i.test(file.name) ? 'image/png' : 'image/jpeg', function(res) {
|
||||
// If it was scaled send the scaled image if it failed then
|
||||
// send the raw image and let the server do the scaling
|
||||
if (res.success) {
|
||||
file.size = res.data.length;
|
||||
sendBinaryBlob(res.data);
|
||||
} else {
|
||||
sendBinaryBlob(nativeFile);
|
||||
}
|
||||
});
|
||||
// if there's no way to slice file without preloading it in memory, preload it
|
||||
} else if (!features.chunks && features.jpgresize) {
|
||||
readFileAsBinary(nativeFile, sendBinaryBlob);
|
||||
} else {
|
||||
sendBinaryBlob(nativeFile); // this works on older WebKits, but fails on fresh ones
|
||||
sendBinaryBlob(nativeFile);
|
||||
}
|
||||
});
|
||||
|
||||
@ -874,10 +941,19 @@
|
||||
read.init(data);
|
||||
|
||||
// Check if data is jpeg
|
||||
if (read.SHORT(0) !== 0xFFD8) {
|
||||
var jpegHeaders = new JPEG_Headers(data);
|
||||
|
||||
if (!jpegHeaders['headers']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete any existing headers that need to be replaced
|
||||
for (var i = jpegHeaders['headers'].length; i > 0; i--) {
|
||||
var hdr = jpegHeaders['headers'][i - 1];
|
||||
read.SEGMENT(hdr.start, hdr.length, '')
|
||||
}
|
||||
jpegHeaders.purge();
|
||||
|
||||
idx = read.SHORT(2) == 0xFFE0 ? 4 + read.SHORT(4) : 2;
|
||||
|
||||
for (var i = 0, max = headers.length; i < max; i++) {
|
||||
@ -1276,8 +1352,7 @@
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
|
||||
EXIF: function() {
|
||||
var Exif;
|
||||
|
||||
@ -1285,12 +1360,14 @@
|
||||
Exif = extractTags(offsets.exifIFD, tags.exif);
|
||||
|
||||
// Fix formatting of some tags
|
||||
Exif.ExifVersion = String.fromCharCode(
|
||||
Exif.ExifVersion[0],
|
||||
Exif.ExifVersion[1],
|
||||
Exif.ExifVersion[2],
|
||||
Exif.ExifVersion[3]
|
||||
);
|
||||
if (Exif.ExifVersion) {
|
||||
Exif.ExifVersion = String.fromCharCode(
|
||||
Exif.ExifVersion[0],
|
||||
Exif.ExifVersion[1],
|
||||
Exif.ExifVersion[2],
|
||||
Exif.ExifVersion[3]
|
||||
);
|
||||
}
|
||||
|
||||
return Exif;
|
||||
},
|
||||
@ -1299,7 +1376,11 @@
|
||||
var GPS;
|
||||
|
||||
GPS = extractTags(offsets.gpsIFD, tags.gps);
|
||||
GPS.GPSVersionID = GPS.GPSVersionID.join('.');
|
||||
|
||||
// iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
|
||||
if (GPS.GPSVersionID) {
|
||||
GPS.GPSVersionID = GPS.GPSVersionID.join('.');
|
||||
}
|
||||
|
||||
return GPS;
|
||||
},
|
||||
|
||||
@ -58,6 +58,7 @@
|
||||
"image/bmp,bmp," +
|
||||
"image/gif,gif," +
|
||||
"image/jpeg,jpeg jpg jpe," +
|
||||
"image/photoshop,psd," +
|
||||
"image/png,png," +
|
||||
"image/svg+xml,svg svgz," +
|
||||
"image/tiff,tiff tif," +
|
||||
@ -68,7 +69,11 @@
|
||||
"video/mp4,mp4," +
|
||||
"video/x-m4v,m4v," +
|
||||
"video/x-flv,flv," +
|
||||
"video/x-ms-wmv,wmv," +
|
||||
"video/avi,avi," +
|
||||
"video/webm,webm," +
|
||||
"video/vnd.rn-realvideo,rv," +
|
||||
"text/csv,csv," +
|
||||
"text/plain,asc txt text diff log," +
|
||||
"application/octet-stream,exe"
|
||||
);
|
||||
@ -183,7 +188,7 @@
|
||||
INIT_ERROR : -500,
|
||||
|
||||
/**
|
||||
* File size error. If the user selects a file that is to large it will be blocked and an error of this type will be triggered.
|
||||
* File size error. If the user selects a file that is too large it will be blocked and an error of this type will be triggered.
|
||||
*
|
||||
* @property FILE_SIZE_ERROR
|
||||
* @final
|
||||
@ -231,6 +236,26 @@
|
||||
* @final
|
||||
*/
|
||||
mimeTypes : mimes,
|
||||
|
||||
/**
|
||||
* In some cases sniffing is the only way around :(
|
||||
*/
|
||||
ua: (function() {
|
||||
var nav = navigator, userAgent = nav.userAgent, vendor = nav.vendor, webkit, opera, safari;
|
||||
|
||||
webkit = /WebKit/.test(userAgent);
|
||||
safari = webkit && vendor.indexOf('Apple') !== -1;
|
||||
opera = window.opera && window.opera.buildNumber;
|
||||
|
||||
return {
|
||||
windows: navigator.platform.indexOf('Win') !== -1,
|
||||
ie: !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName),
|
||||
webkit: webkit,
|
||||
gecko: !webkit && /Gecko/.test(userAgent),
|
||||
safari: safari,
|
||||
opera: !!opera
|
||||
};
|
||||
}()),
|
||||
|
||||
/**
|
||||
* Extends the specified object with another object.
|
||||
@ -491,7 +516,7 @@
|
||||
var mul;
|
||||
|
||||
if (typeof(size) == 'string') {
|
||||
size = /^([0-9]+)([mgk]+)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, ''));
|
||||
size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, ''));
|
||||
mul = size[2];
|
||||
size = +size[1];
|
||||
|
||||
@ -657,7 +682,11 @@
|
||||
}
|
||||
|
||||
// Add event listener
|
||||
if (obj.attachEvent) {
|
||||
if (obj.addEventListener) {
|
||||
func = callback;
|
||||
|
||||
obj.addEventListener(name, func, false);
|
||||
} else if (obj.attachEvent) {
|
||||
|
||||
func = function() {
|
||||
var evt = window.event;
|
||||
@ -672,12 +701,7 @@
|
||||
callback(evt);
|
||||
};
|
||||
obj.attachEvent('on' + name, func);
|
||||
|
||||
} else if (obj.addEventListener) {
|
||||
func = callback;
|
||||
|
||||
obj.addEventListener(name, func, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Log event handler to objects internal Plupload registry
|
||||
if (obj[uid] === undef) {
|
||||
@ -786,7 +810,7 @@
|
||||
plupload.each(eventhash[obj[uid]], function(events, name) {
|
||||
plupload.removeEvent(obj, name, key);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -848,8 +872,9 @@
|
||||
if (!file && files[i].status == plupload.QUEUED) {
|
||||
file = files[i];
|
||||
file.status = plupload.UPLOADING;
|
||||
this.trigger("BeforeUpload", file);
|
||||
this.trigger("UploadFile", file);
|
||||
if (this.trigger("BeforeUpload", file)) {
|
||||
this.trigger("UploadFile", file);
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
@ -857,8 +882,8 @@
|
||||
|
||||
// All files are DONE or FAILED
|
||||
if (count == files.length) {
|
||||
this.trigger("UploadComplete", files);
|
||||
this.stop();
|
||||
this.trigger("UploadComplete", files);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1302,6 +1327,16 @@
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether uploader has any listeners to the specified event.
|
||||
*
|
||||
* @method hasEventListener
|
||||
* @param {String} name Event name to check for.
|
||||
*/
|
||||
hasEventListener : function(name) {
|
||||
return !!events[name.toLowerCase()];
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an event listener by name.
|
||||
|
||||
@ -17,6 +17,11 @@
|
||||
function jsonSerialize(obj) {
|
||||
var value, type = typeof obj, isArray, i, key;
|
||||
|
||||
// Treat undefined as null
|
||||
if (obj === undef || obj === null) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Encode strings
|
||||
if (type === 'string') {
|
||||
value = '\bb\tt\nn\ff\rr\""\'\'\\\\';
|
||||
@ -66,11 +71,6 @@
|
||||
return value;
|
||||
}
|
||||
|
||||
// Treat undefined as null
|
||||
if (obj === undef) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Convert all other types to string
|
||||
return '' + obj;
|
||||
}
|
||||
@ -167,7 +167,8 @@
|
||||
pngresize: true,
|
||||
chunks: true,
|
||||
progress: true,
|
||||
multipart: true
|
||||
multipart: true,
|
||||
multi_selection: true
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user