FR.components.uploadPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
this.initialPanelTitle = this.title;
this.initialDocumentTitle = Settings.title;
this.filesToBeLoaded = [];
this.lastServerError = false;
this.initFlow();
this.btns = {
addFile: new Ext.Action({
text: FR.T('Add Files'),
handler: function(){
this.flow.browseFiles();
},
scope: this, scale: 'medium',
iconCls: 'fa fa-fw fa-upload'
}),
addFolderSep: new Ext.Toolbar.Separator({hidden: true}),
addFolder: new Ext.Action({
text: FR.T('Add Folder'),
handler: function(){
this.flow.browseFiles(true);
},
scope: this, hidden: true, scale: 'medium',
iconCls: 'fa fa-fw fa-upload'
}),
removeFile: new Ext.Action({
text: FR.T('Remove from queue'),
handler: this.removeFile,
scope: this,
iconCls: 'fa fa-fw fa-remove'
}),
cancel: new Ext.Action({
text: FR.T('Cancel all'),
handler: this.cancel, scope: this, style: 'margin-left:15px',
iconCls: 'fa fa-fw fa-remove', cls: 'fr-btn-default'
}),
pauseFile: new Ext.Action({
text: FR.T('Skip file'),
handler: this.pauseFileToggle, scope: this,
iconCls: 'fa fa-fw fa-step-forward'
}),
pauseToggle: new Ext.Button({
text: FR.T('Pause all'),
handler: this.pauseToggle, scope: this,
iconCls: 'fa fa-fw fa-pause', cls: 'fr-btn-default'
})
};
this.statusText = new Ext.Toolbar.TextItem({style: 'color:gray'});
this.pbar = new Ext.ProgressBar({animate: true, width:150});
this.tbar = [
this.btns.addFile,'-',this.btns.addFolder, '->', this.statusText, '-', this.pbar
];
this.buttons = [
this.btns.pauseToggle,'-',this.btns.cancel
];
this.grid = {};
this.grid.contextMenu = new Ext.menu.Menu({
items: [this.btns.pauseFile, this.btns.removeFile]
});
this.grid.store = new Ext.data.ArrayStore({
autoDestroy: true, idIndex: 0,
fields: [
'id', 'name', 'size', 'progress', 'speed', 'remaining',
'status', 'completedBytes', 'lastServerReply', 'file'
]
});
this.grid.panel = new Ext.grid.GridPanel({
border: false, layout: 'fit',
store: this.grid.store, autoScroll: true,
enableDragDrop: true, ddGroup: 'dd',
viewConfig: {
headersDisabled: true, forceFit: true, scrollOffset: 35
},
sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
colModel: new Ext.grid.ColumnModel({
defaults: {width: 120, sortable: false},
columns: [
{header: FR.T('File name'), width: 200, renderer: function(v) {
var ext = FR.utils.getFileExtension(v);
return '
'+v;
}, dataIndex: 'name'},
{header: FR.T('Size'), width: 50, renderer: function(s){return Ext.util.Format.fileSize(s);}, dataIndex: 'size'},
{header: FR.T('Uploaded'), width: 80, dataIndex: 'completedBytes'},
new Ext.ux.ProgressColumn({
header: FR.T('Progress'), dataIndex: 'progress',
width: 130, align: 'center',
renderer: function(v, meta, record) {
if (record.data.status == 'uploading') {
if (v == 1) {
return FR.T('Waiting (100%)');
}
return false;
} else if (record.data.status == 'paused') {
if (v == 0) {
return ''+FR.T('Paused')+'';
} else if (v == 1) {
return false;
} else {
return ''+FR.T('Paused (%1%)').replace('%1', Math.floor(v*100))+'';
}
}
return FR.T(record.data.status);
}
}),
{header: FR.T('Speed'), width: 80, dataIndex: 'speed'},
{header: FR.T('Time remaining'), width: 100, dataIndex: 'remaining'}
]
}),
listeners: {
scope: this,
'rowclick': function (grid, rowIndex, e) {
var clicked = this.grid.store.getAt(rowIndex);
var r = grid.getSelectionModel().getSelected();
if (!r) {
this.grid.panel.getSelectionModel().selectRow(rowIndex);
}
this.showContextMenu(clicked, e);
//console.log(clicked.data.file);
},
'rowcontextmenu': function (grid, rowIndex, e) {
var clicked = this.grid.store.getAt(rowIndex);
var r = grid.getSelectionModel().getSelected();
if (r !== clicked) {
this.grid.panel.getSelectionModel().selectRow(rowIndex);
}
this.showContextMenu(clicked, e);
},
'render': function(grid) {
if (this.triggerSelection == 'files') {
this.flow.browseFiles();
} else if (this.triggerSelection == 'folder') {
this.flow.browseFiles(true);
} else {
if (this.files) {
this.flow.addFiles(this.files);
} else {
if (this.dropEvent) {
this.flow.onDrop(this.dropEvent);
}
}
}
FlowUtils.DropZoneManager.add({
domNode: this.grid.panel.getEl().dom, overClass: 'dragged-over',
findTarget: function(e) {return {el: this.grid.panel.getEl()};},
onDrop: this.flow.onDrop, scope: this
});
}
}
});
Ext.apply(this, {
layout: 'fit',
items: this.grid.panel
});
FR.components.uploadPanel.superclass.initComponent.apply(this, arguments);
},
initFlow: function() {
this.flow = new Flow({
target: '?module=fileman§ion=do&page=up',
chunkSize: Settings.upload_chunk_size, progressCallbacksInterval: 100,
maxChunkRetries: 3, resumeLargerThan: 10485760, maxSimultaneous: Settings.upload_max_simultaneous,
validateChunkResponse: function(status, message) {
if (status != '200') {return 'retry';}
try {var rs = Ext.util.JSON.decode(message);} catch (er){return 'retry';}
if (rs) {if (rs.success) {return 'success';} else {return 'error';}}
}, validateChunkResponseScope: this,
validateGetOffsetResponse: function(file, status, message) {
if (status == 200) {
try {
var rs = Ext.util.JSON.decode(message);
} catch (er){return false;}
if (rs && rs.success) {
if (rs.offset) {
rs.offset = parseInt(rs.offset);
if (!isNaN(rs.offset) && isFinite(rs.offset)) {
file.offset = rs.offset;
}
}
return true;
}
}
}, validateGetOffsetResponseScope: this,
query: {path: this.targetPath}
});
this.flow.on('fileAdded', this.onFileAdded.createDelegate(this));
this.flow.on('filesSubmitted', this.onFilesSubmitted.createDelegate(this));
this.flow.on('fileProgress', this.onFileProgress.createDelegate(this));
this.flow.on('fileError', this.onFileError.createDelegate(this));
this.flow.on('fileSuccess', this.onFileSuccess.createDelegate(this));
this.flow.on('progress', this.onProgress.createDelegate(this));
this.flow.on('complete', this.onComplete.createDelegate(this));
},
start: function() {
this.btns.pauseToggle.setIconClass('fa fa-fw fa-pause');
this.btns.pauseToggle.setText(FR.T('Pause all'));
this.flow.start();
},
cancel: function() {
document.title = this.initialDocumentTitle;
if (this.targetPath == FR.currentPath) {
FR.UI.gridPanel.load(FR.currentPath);
}
this.flow.removeAll();
if (this.errPrompt) {
this.errPrompt.close();
}
this.destroy();
if (this.window) {this.window.close();}
},
pauseToggle: function(btn) {
if (this.flow.paused) {
btn.setIconClass('fa fa-fw fa-pause');
btn.setText(FR.T('Pause all'));
this.flow.start();
this.setTitle(this.initialPanelTitle);
} else {
btn.setIconClass('fa fa-fw fa-play');
btn.setText(FR.T('Resume'));
this.setTitle('Upload paused');
this.flow.pause();
}
},
pauseFileToggle: function() {
var r = this.grid.panel.getSelectionModel().getSelected();
if (r) {
if (r.data.file.queuePaused) {
r.data.file.start();
} else {
r.data.file.pause(true);
}
}
},
removeFile: function() {
var record = this.grid.panel.getSelectionModel().getSelected();
this.flow.removeFile(record.data.file);
if (this.flow.files.length > 0) {
this.grid.store.remove(record);
this.onProgress(this.flow);
}
},
onFileAdded: function(file, event) {
var name = file.name;
if (Settings.upload_blocked_types.length > 0 && Settings.upload_blocked_types.indexOf(FR.utils.getFileExtension(file.name)) != -1) {
FR.UI.feedback(FR.T('You are not allowed to upload the file "%1"').replace('%1', file.name));
return false;
}
if (file.relativePath) {
name = file.relativePath+name;
}
this.filesToBeLoaded.push(new Ext.data.Record(
{
id: file.uniqueIdentifier,
name: name,
size: file.size,
progress: 0,
status: FR.T('Queued'),
file: file
},
file.uniqueIdentifier
));
},
onFilesSubmitted: function() {
if (!this.flow.files.length) {return false;}
this.grid.store.suspendEvents();
Ext.each(this.filesToBeLoaded, function(r) {
this.grid.store.add(r);
}, this);
this.grid.store.resumeEvents();
this.grid.store.fireEvent('datachanged', this.grid.store);
this.filesToBeLoaded = [];
if (!this.flow.paused) {
this.start();
}
this.onProgress(this.flow);
},
onComplete: function() {
document.title = this.initialDocumentTitle;
if (this.flow.completedFiles > 0) {
if (this.targetPath == FR.currentPath) {
FR.UI.gridPanel.load(FR.currentPath);
if (FR.UI.tree.currentSelectedNode.loading == false && FR.UI.tree.currentSelectedNode.loaded == true) {
FR.UI.tree.reloadNode(FR.UI.tree.currentSelectedNode);
}
}
FR.UI.reloadStatusBar();
}
if (this.errPrompt) {
this.errPrompt.close();
}
this.destroy();
if (this.window) {this.window.close();}
},
onProgress: function(flow) {
var completed = Ext.util.Format.fileSize(flow.completedBytes);
var total = Ext.util.Format.fileSize(flow.size);
var countFiles = flow.files.length;
var percent = flow.getProgress();
var status = '';
var remainingFiles = countFiles-flow.completedFiles;
if (countFiles > 1 && remainingFiles > 0) {
status += FR.T('%1 files left').replace('%1', remainingFiles)+', ';
}
status += FR.T('%1 of %2').replace('%1', completed).replace('%2', total);
this.statusText.update(status);
var nicePerc = Math.floor(percent*100)+'%';
this.pbar.updateProgress(percent, nicePerc);
this.setTitle('Uploading.. %1'.replace('%1', nicePerc));
document.title = '['+nicePerc+'] ' + this.initialDocumentTitle;
},
onFileProgress: function(file) {
var r = this.grid.store.getById(file.uniqueIdentifier);
if (!r) {return false;}
if (file.paused) {
if (file.queuePaused) {
r.data['status'] = ''+FR.T('[Skipped]')+'';
} else {
r.data['status'] = 'paused';
}
r.data['speed'] = '';
} else {
if (file.uploadingChunk && file.uploadingChunk.retries > 0) {
r.data['status'] = FR.T('Uploading (Retry #%1)...').replace('%1', file.uploadingChunk.retries);
} else {
r.data['status'] = 'uploading';
}
r.data['remaining'] = this.formatTime(file.timeRemaining());
}
r.data['progress'] = file.progress;
if (file.completedBytes > 0) {
if (file.averageSpeed >= 1) {
r.data['speed'] = Ext.util.Format.fileSize(file.averageSpeed)+'/s';
} else {
r.data['speed'] = '';
}
r.data['completedBytes'] = Ext.util.Format.fileSize(file.completedBytes);
} else {
r.data['speed'] = '';
r.data['completedBytes'] = '';
}
r.commit();
},
onFileSuccess: function(file, message) {
var r = this.grid.store.getById(file.uniqueIdentifier);
try {
var rs = Ext.util.JSON.decode(message);
} catch (er){
r.data['status'] = ''+FR.T('Server error')+'';
this.lastServerError = message;
}
if (rs) {
if (!rs.success) {
this.lastServerError = message;
if (rs.msg) {
r.data['status'] = rs.msg;
this.lastServerError = rs.msg;
} else {
r.data['status'] = ''+FR.T('Server error')+'';
}
} else {
r.data['status'] = ''+rs.msg+'';
}
} else {
r.data['status'] = ''+FR.T('Server error')+'';
this.lastServerError = message;
}
r.commit();
var index = this.grid.store.indexOfId(file.uniqueIdentifier);
this.grid.panel.getView().focusRow(index);
},
onFileError: function(file, message) {
var r = this.grid.store.getById(file.uniqueIdentifier);
try {
var rs = Ext.util.JSON.decode(message);
} catch (er){
r.data['status'] = ''+FR.T('Server error')+'';
this.lastServerError = message;
}
if (rs) {
if (!rs.success) {
this.lastServerError = message;
}
r.data['status'] = ''+FR.T('Failed')+'';
if (rs.msg) {
r.data['status'] += ': '+rs.msg;
this.lastServerError = rs.msg;
}
} else {
r.data['status'] = ''+FR.T('Server error')+'';
this.lastServerError = message;
}
r.commit();
this.btns.pauseToggle.setIconClass('fa fa-fw fa-play');
this.btns.pauseToggle.setText(FR.T('Resume'));
this.errorPrompt(r);
},
showContextMenu: function(record, e) {
if (record.data.file.queuePaused) {
this.btns.pauseFile.setText(FR.T('Resume file'));
this.btns.pauseFile.setIconClass('fa fa-fw fa-play');
} else {
this.btns.pauseFile.setText(FR.T('Skip file'));
this.btns.pauseFile.setIconClass('fa fa-fw fa-step-forward');
}
this.grid.contextMenu.showAt([e.getPageX()+3, e.getPageY()+3]);
},
errorPrompt: function(r) {
if (!this.errPrompt) {
this.errPrompt = {
tabPanel: new Ext.TabPanel({
activeTab: 0, items: [],
listeners: {
'tabchange': function(tp, p) {
if (p) {p.doLayout();}
},
'remove': function(tp, p) {
if (tp.items.getCount() == 0) {
this.errPrompt.win.hide();
}
}, scope: this
}
}),
close: function() {this.win.close();}
};
this.errPrompt.win = new Ext.Window({
title: FR.T('A problem has been encountered!'),
width: 450, height: 240, resizable: false, layout: 'fit',
items: this.errPrompt.tabPanel, hideBorders: true,
buttons: [
{
text: FR.T('Try again'),
iconCls: 'fa fa-fw fa-repeat', cls: 'fr-btn-default',
handler: function() {
this.errPrompt.tabPanel.remove(r.id, true);
r.data.file.start();
this.start();
}, scope: this
},
{
text: FR.T('Skip file'), cls: 'fr-btn-default', style: 'margin-left:15px',
iconCls: 'fa fa-fw fa-step-forward', hidden: (this.grid.store.getCount() < 2),
handler: function() {
this.errPrompt.tabPanel.remove(r.id, true);
r.data.file.pause(true);
this.start();
}, scope: this
},
{
text: FR.T('Cancel all'), cls: 'fr-btn-default',
iconCls: 'fa fa-fw fa-remove', style: 'margin-left:15px',
handler: function() {
this.cancel();
}, scope: this
}
]
});
}
this.errPrompt.win.show();
var tab = this.errPrompt.tabPanel.getItem(r.id);
if (!tab) {
tab = new Ext.Panel({
id: r.id, title: r.data.name, layout: 'fit',
contentEl: Ext.DomHelper.append(Ext.get('theBODY'), {tag: 'IFRAME', frameborder: 0, height: '100%', width: '100%'})
});
this.errPrompt.tabPanel.add(tab);
}
tab.show();
var messageArea = tab.contentEl;
if (messageArea.contentDocument) {
if (messageArea.contentDocument.document) {
var frameDoc = messageArea.contentDocument.document;
} else {
var frameDoc = messageArea.contentDocument
}
} else {
if (messageArea.contentWindow.document) {
var frameDoc = messageArea.contentWindow.document
}
}
frameDoc.open();
frameDoc.write(
''
);
frameDoc.write(this.lastServerError);
frameDoc.close();
},
formatTime: function(secs) {
if (secs == Number.POSITIVE_INFINITY) {return '';}
var hours = Math.floor(secs / (60 * 60));
var divisor_for_minutes = secs % (60 * 60);
var minutes = Math.floor(divisor_for_minutes / 60);
var divisor_for_seconds = divisor_for_minutes % 60;
var seconds = Math.ceil(divisor_for_seconds);
var str = '';
if (hours > 24) {
return FR.T('too long');
}
if (hours > 0) {
str += FR.T('%1 hours').replace('%1', hours);
}
if (minutes > 0) {
if (str != '') {str += ', ';}
str += FR.T('%1 minutes').replace('%1', minutes);
}
if (seconds > 0) {
if (str != '') {str += ', ';}
str += FR.T('%1 seconds').replace('%1', seconds);
}
return str;
},
onRender: function() {
FR.components.uploadPanel.superclass.onRender.apply(this, arguments);
if (FlowUtils.browserSupport.folders) {
this.btns.addFolder.show();
this.btns.addFolderSep.show();
}
}
});
Ext.reg('uploadPanel', FR.components.uploadPanel);