📄 ext.ux.uploaddialog.js
字号:
/**
* This namespace should be in another file but I dicided to put it here for consistancy.
*/
Ext.namespace('Ext.ux.Utils');
/**
* This class implements event queue behaviour.
*
* @class Ext.ux.Utils.EventQueue
* @param function handler Event handler.
* @param object scope Handler scope.
*/
Ext.ux.Utils.EventQueue = function(handler, scope)
{
if (!handler) {
throw 'Handler is required.';
}
this.handler = handler;
this.scope = scope || window;
this.queue = [];
this.is_processing = false;
/**
* Posts event into the queue.
* * @access public
* @param mixed event Event identificator.
* @param mixed data Event data.
*/
this.postEvent = function(event, data)
{
data = data || null;
this.queue.push({event: event, data: data});
if (!this.is_processing) {
this.process();
}
}
this.flushEventQueue = function()
{
this.queue = [];
},
/**
* @access private
*/
this.process = function()
{
while (this.queue.length > 0) {
this.is_processing = true;
var event_data = this.queue.shift();
this.handler.call(this.scope, event_data.event, event_data.data);
}
this.is_processing = false;
}
}
/**
* This class implements Mili's finite state automata behaviour.
*
* Transition / output table format:
* {
* 'state_1' : {
* 'event_1' : [
* {
* p|predicate: function, // Transition predicate, optional, default to true.
* // If array then conjunction will be applyed to the operands.
* // Predicate signature is (data, event, this).
* a|action: function|array, // Transition action, optional, default to Ext.emptyFn.
* // If array then methods will be called sequentially.
* // Action signature is (data, event, this).
* s|state: 'state_x', // New state - transition destination, optional, default to
* // current state.
* scope: object // Predicate and action scope, optional, default to
* // trans_table_scope or window.
* }
* ]
* },
*
* 'state_2' : {
* ...
* }
* ...
* }
*
* @param mixed initial_state Initial state.
* @param object trans_table Transition / output table.
* @param trans_table_scope Transition / output table's methods scope.
*/
Ext.ux.Utils.FSA = function(initial_state, trans_table, trans_table_scope)
{
this.current_state = initial_state;
this.trans_table = trans_table || {};
this.trans_table_scope = trans_table_scope || window;
Ext.ux.Utils.FSA.superclass.constructor.call(this, this.processEvent, this);
}
Ext.extend(Ext.ux.Utils.FSA, Ext.ux.Utils.EventQueue, {
current_state : null,
trans_table : null,
trans_table_scope : null,
/**
* Returns current state
*
* @access public
* @return mixed Current state.
*/
state : function()
{
return this.current_state;
},
/**
* @access public
*/
processEvent : function(event, data)
{
var transitions = this.currentStateEventTransitions(event);
if (!transitions) {
throw "State '" + this.current_state + "' has no transition for event '" + event + "'.";
}
for (var i = 0, len = transitions.length; i < len; i++) {
var transition = transitions[i];
var predicate = transition.predicate || transition.p || true;
var action = transition.action || transition.a || Ext.emptyFn;
var new_state = transition.state || transition.s || this.current_state;
var scope = transition.scope || this.trans_table_scope;
if (this.computePredicate(predicate, scope, data, event)) {
this.callAction(action, scope, data, event);
this.current_state = new_state;
return;
}
}
throw "State '" + this.current_state + "' has no transition for event '" + event + "' in current context";
},
/**
* @access private
*/
currentStateEventTransitions : function(event)
{
return this.trans_table[this.current_state] ?
this.trans_table[this.current_state][event] || false
:
false;
},
/**
* @access private
*/
computePredicate : function(predicate, scope, data, event)
{
var result = false;
switch (Ext.type(predicate)) {
case 'function':
result = predicate.call(scope, data, event, this);
break;
case 'array':
result = true;
for (var i = 0, len = predicate.length; result && (i < len); i++) {
if (Ext.type(predicate[i]) == 'function') {
result = predicate[i].call(scope, data, event, this);
}
else {
throw [
'Predicate: ',
predicate[i],
' is not callable in "',
this.current_state,
'" state for event "',
event
].join('');
}
}
break;
case 'boolean':
result = predicate;
break;
default:
throw [
'Predicate: ',
predicate,
' is not callable in "',
this.current_state,
'" state for event "',
event
].join('');
}
return result;
},
/**
* @access private
*/
callAction : function(action, scope, data, event)
{
switch (Ext.type(action)) {
case 'array':
for (var i = 0, len = action.length; i < len; i++) {
if (Ext.type(action[i]) == 'function') {
action[i].call(scope, data, event, this);
}
else {
throw [
'Action: ',
action[i],
' is not callable in "',
this.current_state,
'" state for event "',
event
].join('');
}
}
break;
case 'function':
action.call(scope, data, event, this);
break;
default:
throw [
'Action: ',
action,
' is not callable in "',
this.current_state,
'" state for event "',
event
].join('');
}
}
});
// ---------------------------------------------------------------------------------------------- //
/**
* Ext.ux.UploadDialog namespace.
*/
Ext.namespace('Ext.ux.UploadDialog');
/**
* File upload browse button.
*
* @class Ext.ux.UploadDialog.BrowseButton
*/
Ext.ux.UploadDialog.BrowseButton = Ext.extend(Ext.Button,
{
input_name : 'file',
input_file : null,
original_handler : null,
original_scope : null,
/**
* @access private
*/
initComponent : function()
{
Ext.ux.UploadDialog.BrowseButton.superclass.initComponent.call(this);
this.original_handler = this.handler || null;
this.original_scope = this.scope || window;
this.handler = null;
this.scope = null;
},
/**
* @access private
*/
onRender : function(ct, position)
{
Ext.ux.UploadDialog.BrowseButton.superclass.onRender.call(this, ct, position);
this.createInputFile();
},
/**
* @access private
*/
createInputFile : function()
{
var button_container = this.el.child('.x-btn-center');
button_container.position('relative');
this.input_file = Ext.DomHelper.append(
button_container,
{
tag: 'input',
type: 'file',
size: 1,
name: this.input_name || Ext.id(this.el),
style: 'position: absolute; display: block; border: none; cursor: pointer'
},
true
);
var button_box = button_container.getBox();
this.input_file.setStyle('font-size', (button_box.width * 0.5) + 'px');
var input_box = this.input_file.getBox();
var adj = {x: 3, y: 3}
if (Ext.isIE) {
adj = {x: 0, y: 3}
}
this.input_file.setLeft(button_box.width - input_box.width + adj.x + 'px');
this.input_file.setTop(button_box.height - input_box.height + adj.y + 'px');
this.input_file.setOpacity(0.0);
if (this.handleMouseEvents) {
this.input_file.on('mouseover', this.onMouseOver, this);
this.input_file.on('mousedown', this.onMouseDown, this);
}
if(this.tooltip){
if(typeof this.tooltip == 'object'){
Ext.QuickTips.register(Ext.apply({target: this.input_file}, this.tooltip));
}
else {
this.input_file.dom[this.tooltipType] = this.tooltip;
}
}
this.input_file.on('change', this.onInputFileChange, this);
this.input_file.on('click', function(e) { e.stopPropagation(); });
},
/**
* @access public
*/
detachInputFile : function(no_create)
{
var result = this.input_file;
no_create = no_create || false;
if (typeof this.tooltip == 'object') {
Ext.QuickTips.unregister(this.input_file);
}
else {
this.input_file.dom[this.tooltipType] = null;
}
this.input_file.removeAllListeners();
this.input_file = null;
if (!no_create) {
this.createInputFile();
}
return result;
},
/**
* @access public
*/
getInputFile : function()
{
return this.input_file;
},
/**
* @access public
*/
disable : function()
{
Ext.ux.UploadDialog.BrowseButton.superclass.disable.call(this);
this.input_file.dom.disabled = true;
},
/**
* @access public
*/
enable : function()
{
Ext.ux.UploadDialog.BrowseButton.superclass.enable.call(this);
this.input_file.dom.disabled = false;
},
/**
* @access public
*/
destroy : function()
{
var input_file = this.detachInputFile(true);
input_file.remove();
input_file = null;
Ext.ux.UploadDialog.BrowseButton.superclass.destroy.call(this);
},
/**
* @access private
*/
onInputFileChange : function()
{
if (this.original_handler) {
this.original_handler.call(this.original_scope, this);
}
}
});
/**
* Toolbar file upload browse button.
*
* @class Ext.ux.UploadDialog.TBBrowseButton
*/
Ext.ux.UploadDialog.TBBrowseButton = Ext.extend(Ext.ux.UploadDialog.BrowseButton,
{
hideParent : true,
onDestroy : function()
{
Ext.ux.UploadDialog.TBBrowseButton.superclass.onDestroy.call(this);
if(this.container) {
this.container.remove();
}
}
});
/**
* Record type for dialogs grid.
*
* @class Ext.ux.UploadDialog.FileRecord
*/
Ext.ux.UploadDialog.FileRecord = Ext.data.Record.create([
{name: 'filename'},
{name: 'state', type: 'int'},
{name: 'note'},
{name: 'input_element'}
]);
Ext.ux.UploadDialog.FileRecord.STATE_QUEUE = 0;
Ext.ux.UploadDialog.FileRecord.STATE_FINISHED = 1;
Ext.ux.UploadDialog.FileRecord.STATE_FAILED = 2;
Ext.ux.UploadDialog.FileRecord.STATE_PROCESSING = 3;
/**
* Dialog class.
*
* @class Ext.ux.UploadDialog.Dialog
*/
Ext.ux.UploadDialog.Dialog = function(config)
{
var default_config = {
border: false,
width: 450,
height: 300,
minWidth: 450,
minHeight: 300,
plain: true,
constrainHeader: true,
draggable: true,
closable: true,
maximizable: false,
minimizable: false,
resizable: true,
autoDestroy: true,
closeAction: 'hide',
title: this.i18n.title,
cls: 'ext-ux-uploaddialog-dialog',
// --------
url: '',
base_params: {},
permitted_extensions: [],
reset_on_hide: true,
allow_close_on_upload: false,
upload_autostart: false,
post_var_name: 'file'
}
config = Ext.applyIf(config || {}, default_config);
config.layout = 'absolute';
Ext.ux.UploadDialog.Dialog.superclass.constructor.call(this, config);
}
Ext.extend(Ext.ux.UploadDialog.Dialog, Ext.Window, {
fsa : null,
state_tpl : null,
form : null,
grid_panel : null,
progress_bar : null,
is_uploading : false,
initial_queued_count : 0,
upload_frame : null,
/**
* @access private
*/
//--------------------------------------------------------------------------------------------- //
initComponent : function()
{
Ext.ux.UploadDialog.Dialog.superclass.initComponent.call(this);
// Setting automata protocol
var tt = {
// --------------
'created' : {
// --------------
'window-render' : [
{
action: [this.createForm, this.createProgressBar, this.createGrid],
state: 'rendering'
}
],
'destroy' : [
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -