Index: branches/5.1.x/core/admin_templates/js/uploader/uploader.js =================================================================== diff -u -r13086 -r13658 --- branches/5.1.x/core/admin_templates/js/uploader/uploader.js (.../uploader.js) (revision 13086) +++ branches/5.1.x/core/admin_templates/js/uploader/uploader.js (.../uploader.js) (revision 13658) @@ -4,7 +4,6 @@ function Uploader(id, params) { this.id = id; - this._moved = false; // flash was moved outside scroll container // normalize params if (isNaN(parseInt(params.multiple))) { @@ -23,12 +22,10 @@ this.files_count = 0; this.files = new Array(); - this.deleted = new Array() + this.deleted = new Array(); this.uploadURL = params.uploadURL; this.deleteURL = params.deleteURL; - - this._resetCounters(); } /* ==== Private methods ==== */ @@ -45,6 +42,7 @@ allowedFiletypesDescription : 'All Files', allowedFilesize : 0, // Default zero means "unlimited" multiple : 0, + thumb_format: '', fileQueueLimit : 0, buttonImageURL : '', buttonWidth : 1, @@ -81,6 +79,7 @@ Uploader.prototype._prepareFiles = function() { var ids = ''; var names = ''; + for (var f = 0; f < this.files.length; f++) { if (isset(this.files[f].uploaded) && !isset(this.files[f].temp)) { continue; @@ -92,38 +91,24 @@ ids = ids.replace(/\|$/, '', ids); names = names.replace(/\|$/, '', names); + document.getElementById(this.id+'[tmp_ids]').value = ids; document.getElementById(this.id+'[tmp_names]').value = names; document.getElementById(this.id+'[tmp_deleted]').value = this.deleted.join('|'); } -Uploader.prototype._getMicroTime = function() { - var $now = new Date(); - return Math.round($now.getTime() / 1000); // because miliseconds are returned too -} +Uploader.prototype._formatSize = function (bytes) { + var kb = Math.round(bytes / 1024); -Uploader.prototype._getEstimatedTime = function() { - return Math.ceil((100 - this.ProgressPercent) * this.ProgressTime / this.ProgressPercent); -} + if (kb < 1024) { + return kb + ' KB'; + } -Uploader.prototype._formatTime = function ($seconds) { - $seconds = parseInt($seconds); + var mb = Math.round(kb / 1024 * 100) / 100; - var $minutes = Math.floor($seconds / 60); - if ($minutes < 10) $minutes = '0' + $minutes; - $seconds = $seconds % 60; - if ($seconds < 10) $seconds = '0' + $seconds; - - return $minutes + ':' + $seconds; + return mb + ' MB'; } -Uploader.prototype._formatSize = function (bytes) { - var kb = Math.round(bytes / 1024); - if (kb < 1024) return kb+'Kb'; - var mb = Math.round(kb / 1024 * 100)/100; - return mb+'Mb'; -} - Uploader.prototype._executeNextEvent = function () { var f = this._eventQueue ? this._eventQueue.shift() : null; if (typeof(f) === 'function') { @@ -133,34 +118,8 @@ /* ==== Public methods ==== */ Uploader.prototype.init = function() { - if (this.params.buttonPlaceholderId !== false) { - // use given container - var holder = document.getElementById(this.params.buttonPlaceholderId); - } - else { - // create container on the fly - var holder = document.createElement('DIV'); - document.body.appendChild(holder); - } - - if (UploadsManager.useTransparency) { - document.getElementById($form_name).style.display = 'block'; - } - - // moving out progress div to overcome loosing of flash object after setting opacity - this.div = document.getElementById(this.id+'_progress'); - var clone = this.div.cloneNode(true); - this.div.parentNode.removeChild(this.div) - this.div = document.body.appendChild(clone); this.IconPath = this.params.IconPath ? this.params.IconPath : '../admin_templates/img/browser/icons'; - this.filename = document.getElementById(this.id+'_progress_filename'); - this.progress = document.getElementById(this.id+'_progress_progress'); - this.elapsed = document.getElementById(this.id+'_progress_elapsed'); - this.remaining = document.getElementById(this.id+'_progress_remaining'); - this.percent = document.getElementById(this.id+'_percent'); - this.done = document.getElementById(this.id+'_done'); - // initialize flash object this.flash_id = UploadsManager._nextFlashId(); @@ -184,7 +143,7 @@ this.swf.addParam('wmode', escape(this.params.wmode)); this.swf.addVariable('movieName', escape(this.flash_id)); - this.swf.addVariable('fileUploadLimit', escape(this.params.multiple)); + this.swf.addVariable('fileUploadLimit', 0); this.swf.addVariable('fileQueueLimit', escape(this.params.fileQueueLimit)); this.swf.addVariable('fileSizeLimit', escape(this.params.allowedFilesize)); // in kilobytes this.swf.addVariable('fileTypes', escape(this.params.allowedFiletypes)); @@ -207,62 +166,50 @@ this.swf.addVariable('debugEnabled', escape('true')); // flash var } - if (this.params.buttonPlaceholderId === false || !UploadsManager.useTransparency) { - // only write flash, when button placeholder is not used - this.swf.write(holder); - this.flash = document.getElementById(this.flash_id); - } + var $me = this; + Application.setHook( + 'm:OnAfterFormInit', + function () { + $me.renderBrowseButton(); + } + ) + if (this.params.urls != '') { var urls = this.params.urls.split('|'); var names = this.params.names.split('|'); var sizes = this.params.sizes.split('|'); + for (var i = 0; i < urls.length; i++) { var a_file = { id : names[i], name : names[i], url : urls[i], size: sizes[i], - uploaded : 1 - } - this.files.push(a_file) + uploaded : 1, + progress: 100 + }; + + this.files.push(a_file); this.files_count++; } + this.updateInfo(); } } -Uploader.prototype.moveOutside = function() { - // move flash outside scroll_container, but keeps it's position on screen - if (!UploadsManager.useTransparency || this._moved) { - // moving only needed when transparency us used (e.g. in admin) - return ; - } +Uploader.prototype.renderBrowseButton = function() { + var holder = document.getElementById(this.params.buttonPlaceholderId); + this.swf.write(holder); - var $new_container = document.createElement('DIV'); - $new_container.id = this.params.buttonPlaceholderId + '_outside'; - $new_container.style.position = 'absolute'; - - var $old_container = document.getElementById(this.params.buttonPlaceholderId); - $new_container.style.top = getRealTop($old_container) + 'px'; - $new_container.style.left = getRealLeft($old_container) + 'px'; - - var $holder_dimensions = getDimensions($old_container); - $new_container.style.width = $holder_dimensions.innerWidth + 'px'; - $new_container.style.height = $holder_dimensions.innerHeight + 'px'; - - document.body.appendChild($new_container); - - this.swf.write($new_container); // write flash outside scroll_container - this.flash = document.getElementById(this.flash_id); // fix reference to flash object - - this._moved = true; + this.flash = document.getElementById(this.flash_id); } Uploader.prototype.remove = function() { - var id = this._moved ? this.params.buttonPlaceholderId + '_outside' : this.params.buttonPlaceholderId; + var id = this.params.buttonPlaceholderId; var obj = document.getElementById(id); + if (obj/* && obj.nodeName == "OBJECT"*/) { var u = navigator.userAgent.toLowerCase(); var p = navigator.platform.toLowerCase(); @@ -298,98 +245,167 @@ } } -Uploader.prototype.syncBrowseButton = function() { - // when flash is moved outside scroll_container, keeps it's position on screen during scroll operations - if (!this._moved) { - return ; - } +Uploader.prototype.isImage = function($filename) { + $filename.match(/\.([^.]*)$/); + var $ext = RegExp.$1.toLowerCase(); - var $scroll_container = UploadsManager._getScrollContainer(); - var $scroll_container_top = getRealTop($scroll_container); - var $scroll_container_left = getRealLeft($scroll_container); + return $ext.match(/^(bmp|gif|jpg|jpeg|png)$/); +} - var $scroll_top = $scroll_container.scrollTop; - var $scroll_left = $scroll_container.scrollLeft; +Uploader.prototype.getFileIcon = function($filename) { + $filename.match(/\.([^.]*)$/); + var ext = RegExp.$1.toLowerCase(); - var $old_container = document.getElementById(this.params.buttonPlaceholderId); - var $new_container = document.getElementById(this.params.buttonPlaceholderId + '_outside'); + $icon = ext.match(/^(ai|avi|bmp|cs|dll|doc|dot|exe|fla|gif|htm|html|jpg|js|mdb|mp3|pdf|ppt|rdp|swf|swt|txt|vsd|xls|xml|zip)$/) ? ext : 'default.icon'; + return this.IconPath + '/' + $icon + '.gif'; +} - var $old_container_top = getRealTop($old_container); - var $old_container_left = getRealLeft($old_container); +Uploader.prototype.getQueueElement = function($file) { + var $ret = ''; + var $icon_image = this.getFileIcon($file.name); + var $file_label = $file.name + ' (' + this._formatSize($file.size) + ')'; + var $need_preview = false; - if ($scroll_container_top <= $old_container_top - $scroll_top) { - // prevents moving outside $scroll_container - $new_container.style.top = ($old_container_top - $scroll_top) + 'px'; + if (isset($file.uploaded)) { + // add deletion checkbox + $need_preview = (this.params.thumb_format.length > 0) && this.isImage($file.name); + $ret += '
'; + + // add icon based on file type + $ret += '
'; + + if ($need_preview) { + $ret += ''; + } + else { + $ret += ''; + } + + $ret += '
' + + // add filename + preview link + $ret += '
' + $file_label + '
'; } else { - // move browse button outside visible area - $new_container.style.top = -this.params.buttonHeight + 'px'; + // add icon based on file type + $ret += '
'; + + // add filename + $ret += '
' + $file_label + '
'; + + // add empty progress bar + $ret += '
'; + + // add cancel upload link + $ret += '
Cancel
'; } - if ($scroll_container_left <= $old_container_left - $scroll_left) { - // prevents moving outside $scroll_container - $new_container.style.left = ($old_container_left - $scroll_left) + 'px'; + $ret += '
'; + $ret = $('
' + $ret + '
'); + + // set click events + var $me = this; + + $('.delete-file-btn', $ret).click( + function ($e) { + $(this).attr('checked', UploadsManager.DeleteFile($me.id, $file.name) ? '' : 'checked'); + } + ); + + $('.cancel-upload-btn', $ret).click( + function ($e) { + UploadsManager.CancelFile(UploadsManager._getUploader($file).id, $file.id); + return false; + } + ); + + // prepare auto-loading preview + var $image = $('img.thumbnail-image', $ret); + + if ($image.length > 0) { + var $tmp_image = new Image(); + $tmp_image.src = $image.attr('large_src'); + + $($tmp_image).load ( + function ($e) { + $image.attr('src', $tmp_image.src).addClass('thumbnail'); + } + ); } - else { - // move browse button outside visible area - $new_container.style.left = -this.params.buttonWidth + 'px'; - } + + return $ret; } -Uploader.prototype.updateInfo = function() { - var $o = ''; - var $icon = ''; - var $filename = ''; - var $delete_code = ''; +Uploader.prototype.updateQueueFile = function($file_index, $delete_file) { + $queue_container = $( jq('#' + this.id + '_queueinfo') ); - for (var f = 0; f < this.files.length; f++) { - this.files[f].name.match(/\.([^.]*)$/); - var ext = RegExp.$1.toLowerCase(); - $icon = ext.match(/^(ai|avi|bmp|cs|dll|doc|dot|exe|fla|gif|htm|html|jpg|js|mdb|mp3|pdf|ppt|rdp|swf|swt|txt|vsd|xls|xml|zip)$/) ? ext : 'default.icon'; - $icon = ' '; + if ($delete_file !== undefined && $delete_file) { + $( jq('#' + this.files[$file_index].id + '_queue_row') ).remove(); - if (isset(this.files[f].uploaded)) { - $filename = '' + this.files[f].name + ' (' + this._formatSize(this.files[f].size) + ')'; - $delete_code = 'UploadsManager.DeleteFile(\'' + this.id + '\', \'' + this.files[f].name + '\')'; + if (this.files.length == 1) { + $queue_container.css('margin-top', '0px'); } + return ; + } + + $ret = this.getQueueElement( this.files[$file_index] ); + var $row = $( jq('#' + this.files[$file_index].id + '_queue_row') ); + + if ($row.length > 0) { + // file round -> replace + $row.replaceWith($ret); + } + else { + // file not found - add + $( jq('#' + this.id + '_queueinfo') ).append($ret); + $queue_container.css('margin-top', '8px'); + } +} + +Uploader.prototype.updateInfo = function($file_index, $prepare_only) { + if ($prepare_only === undefined || !$prepare_only) { + if ($file_index === undefined) { + for (var f = 0; f < this.files.length; f++) { + this.updateQueueFile(f); + } + } else { - $filename = this.files[f].name + ' (' + this._formatSize(this.files[f].size) + ')'; - $delete_code = 'UploadsManager.CancelFile(\'' + UploadsManager._getUploader(this.files[f]).id + '\', \'' + this.files[f].id + '\')'; + this.updateQueueFile($file_index); } - - $o += '' + $icon + '' + $filename + ' [Delete]'; } - document.getElementById(this.id+'_queueinfo').innerHTML = '' + $o + '
'; this._prepareFiles(); +} - // sync position of all uploaders below current, because file queue height change will not affect their positions - UploadsManager.iterate('syncBrowseButton', 'timeout:0'); +Uploader.prototype.updateProgressOnly = function ($file_index) { + var $progress_code = '
'; + + $('#' + this.files[$file_index].id + '_progress').html($progress_code); } Uploader.prototype.removeFile = function (file) { - var n_files = new Array(); var count = 0; - var $new_total = 0; + var n_files = new Array(); + var $to_delete = []; + for (var f = 0; f < this.files.length; f++) { if (this.files[f].id != file.id && this.files[f].name != file.id) { n_files.push(this.files[f]); - if (!isset(this.files[f].uploaded)) { - $new_total += file.size; - } count++; } + else { + $to_delete.push(f); + } } - if (this.StartTime == 0) { - // don't update total during upload, because that breaks progress bar - this.total = $new_total; + for (var $i = 0; $i < $to_delete.length; $i++) { + this.updateQueueFile($to_delete[$i], true); } this.files = n_files; this.files_count = count; - this.updateInfo(); + this.updateInfo(undefined, true); } Uploader.prototype.hasQueue = function() { @@ -405,121 +421,78 @@ } Uploader.prototype.startUpload = function() { - UploadsManager.uploadCancelled = this.uploadCancelled = false; + this.uploadCancelled = false; if (!this.hasQueue()) { return; } - if (UploadsManager.useTransparency) { - Request.setOpacity(30, UploadsManager._getFormContainer()); - } - - if (!document.all) { - var $winW = window.innerWidth; - var $winH = window.innerHeight; - } - else { - var $winW = window.document.body.offsetWidth; - var $winH = window.document.body.offsetHeight; - } - - var left = Math.round(($winW - 350)/2)+'px'; - var top = Math.round(($winH - 110)/2)+'px'; - - this.div.style.top = top; - this.div.style.left = left; - this.div.style.display = 'block'; - - if (UploadsManager.useTransparency) { - Request.setOpacity(100, this.div); - } - - this.StartTime = this._getMicroTime(); - this.ProgressPercent = 0; // progress percent - this.ProgressTime = new Array(); - - this.uploaded = 0; - this.total = 0; - for (var f = 0; f < this.files.length; f++) { - if (isset(this.files[f].uploaded)) { - // get total bytes of non-uploaded files - continue; - } - this.total += this.files[f].size; - } - this.callFlash('StartUpload'); } Uploader.prototype.cancelUpload = function() { this.callFlash('StopUpload'); - var $stats = this.callFlash('GetStats'); + while ($stats.files_queued > 0) { this.callFlash('CancelUpload'); - $stats = this.callFlash('GetStats'); } - UploadsManager.uploadCancelled = this.uploadCancelled = true; + this.uploadCancelled = true; } Uploader.prototype.UploadFileStart = function(file) { - this.filename.innerHTML = file.name; + var $file_index = this.getFileIndex(file); + this.files[$file_index].progress = 0; + this.updateProgressOnly($file_index); this.callFlash('AddFileParam', [file.id, 'field', this.params.field]); this.callFlash('AddFileParam', [file.id, 'id', file.id]); this.callFlash('AddFileParam', [file.id, 'flashsid', this.params.flashsid]); - UploadsManager.iterate('disableBrowse', true); // disable all "Browse" buttons (not just for current uploader)! - // we can prevent user from adding any files here :) this.callFlash('ReturnUploadStart', [true]); } Uploader.prototype.UploadProgress = function(file, bytesLoaded, bytesTotal) { - this.cur_file_uploaded = bytesLoaded; - var uploaded = this.uploaded + this.cur_file_uploaded; - this.ProgressTime = this._getMicroTime() - this.StartTime; + var $file_index = this.getFileIndex(file); + this.files[$file_index].progress = Math.round(bytesLoaded / bytesTotal * 100); + this.updateProgressOnly($file_index); +} - var speed = 0; - if (this.ProgressTime > 0) { - speed = Math.round(uploaded / this.ProgressTime * 100) / 100; +Uploader.prototype.UploadFileComplete = function(file) { + var $file_index = this.getFileIndex(file); + + if ($file_index !== false) { + // in case if file upload was cancelled, then no info here + this.files[$file_index].uploaded = 1; + this.files[$file_index].progress = 100; + this.files[$file_index].temp = 1; + this.files[$file_index].url = this.params.tmp_url.replace('#ID#', file.id).replace('#FILE#', file.name).replace('#FIELD#', this.params.field); } - this.progress.innerHTML = this._formatSize(uploaded) + ' / ' + this._formatSize(this.total) + ' (' + this._formatSize(speed) + '/s)'; - this.ProgressPercent = Math.round(uploaded / this.total * 100); - this.done.style.width = this.ProgressPercent + '%'; - this.percent.innerHTML = this.ProgressPercent + '%'; + this.updateInfo($file_index); - this.elapsed.innerHTML = this._formatTime(this.ProgressTime ); - this.remaining.innerHTML = this._formatTime( this._getEstimatedTime() ); + // upload next file in queue + var $stats = this.callFlash('GetStats'); + + if ($stats.files_queued > 0) { + this.callFlash('StartUpload'); + } + else { + UploadsManager.UploadQueueComplete(this); + } } -Uploader.prototype.UploadFileComplete = function(file) { - this.uploaded += this.cur_file_uploaded; +Uploader.prototype.getFileIndex = function(file) { for (var f = 0; f < this.files.length; f++) { if (this.files[f].id == file.id) { - this.files[f].uploaded = 1; - this.files[f].temp = 1; - this.files[f].url = this.params.tmp_url.replace('#ID#', file.id).replace('#FILE#', file.name).replace('#FIELD#', this.params.field); + return f; } } - this.updateInfo(); - // upload next file in queue - var $stats = this.callFlash('GetStats'); - if ($stats.files_queued > 0 && !UploadsManager.uploadCancelled) { - this.callFlash('StartUpload'); - } else { - // all files in queue are uploaded OR upload was cancelled globally - if (UploadsManager.uploadCancelled) { - // when upload was cancelled globally -> cancel it for any other uploader - this.cancelUpload(); - } - UploadsManager.UploadQueueComplete(this); - } + return false; } Uploader.prototype.queueEvent = function (function_body) { @@ -598,32 +571,17 @@ }; Uploader.prototype.onFlashReady = function() { - this.disableBrowse(false); - UploadsManager.iterate('syncBrowseButton'); -} + var $me = this; -Uploader.prototype.disableBrowse = function($disabled) { - if ($disabled === undefined) { - $disabled = true; - } - this.queueEvent( function() { - this.callFlash('SetButtonDisabled', [$disabled]); + setTimeout( + function () { + // enable upload button, when flash is fully loaded + $me.callFlash('SetButtonDisabled', [false]); + }, 0 + ) + } ); -} - -Uploader.prototype._resetCounters = function() { - this.StartTime = 0; // time, when upload was started - this.ProgressPercent = 0; // upload progress in percents - this.ProgressTime = 0; // flash upload process callback times - this.total = 0; // total bytes to upload (from all queued files) - this.uploaded = 0; // total uploaded bytes (from all queued files) -} - -Uploader.prototype.finalizeUpload = function() { - // hide progress bar only of uploader, that completed it's queue - this.div.style.display = 'none'; - this._resetCounters(); } \ No newline at end of file