uploaddialog.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486
  1. /**
  2. * This namespace should be in another file but I dicided to put it here for consistancy.
  3. */
  4. Ext.namespace('Ext.ux.Utils');
  5. /**
  6. * This class implements event queue behaviour.
  7. *
  8. * @class Ext.ux.Utils.EventQueue
  9. * @param function handler Event handler.
  10. * @param object scope Handler scope.
  11. */
  12. Ext.ux.Utils.EventQueue = function(handler, scope) {
  13. if (!handler) {
  14. throw 'Handler is required.';
  15. }
  16. this.handler = handler;
  17. this.scope = scope || window;
  18. this.queue = [];
  19. this.is_processing = false;
  20. /**
  21. * Posts event into the queue.
  22. *
  23. * @access public
  24. * @param mixed event Event identificator.
  25. * @param mixed data Event data.
  26. */
  27. this.postEvent = function(event, data) {
  28. data = data || null;
  29. this.queue.push({event: event, data: data});
  30. if (!this.is_processing) {
  31. this.process();
  32. }
  33. }
  34. this.flushEventQueue = function() {
  35. this.queue = [];
  36. },
  37. /**
  38. * @access private
  39. */
  40. this.process = function() {
  41. while (this.queue.length > 0) {
  42. this.is_processing = true;
  43. var event_data = this.queue.shift();
  44. this.handler.call(this.scope, event_data.event, event_data.data);
  45. }
  46. this.is_processing = false;
  47. }
  48. };
  49. /**
  50. * This class implements Mili's finite state automata behaviour.
  51. *
  52. * Transition / output table format:
  53. * {
  54. * 'state_1' : {
  55. * 'event_1' : [
  56. * {
  57. * p|predicate: function, // Transition predicate, optional, default to true.
  58. * // If array then conjunction will be applyed to the operands.
  59. * // Predicate signature is (data, event, this).
  60. * a|action: function|array, // Transition action, optional, default to Ext.emptyFn.
  61. * // If array then methods will be called sequentially.
  62. * // Action signature is (data, event, this).
  63. * s|state: 'state_x', // New state - transition destination, optional, default to
  64. * // current state.
  65. * scope: object // Predicate and action scope, optional, default to
  66. * // trans_table_scope or window.
  67. * }
  68. * ]
  69. * },
  70. *
  71. * 'state_2' : {
  72. * ...
  73. * }
  74. * ...
  75. * }
  76. *
  77. * @param mixed initial_state Initial state.
  78. * @param object trans_table Transition / output table.
  79. * @param trans_table_scope Transition / output table's methods scope.
  80. */
  81. Ext.ux.Utils.FSA = function(initial_state, trans_table, trans_table_scope) {
  82. this.current_state = initial_state;
  83. this.trans_table = trans_table || {};
  84. this.trans_table_scope = trans_table_scope || window;
  85. Ext.ux.Utils.FSA.superclass.constructor.call(this, this.processEvent, this);
  86. };
  87. Ext.extend(Ext.ux.Utils.FSA, Ext.ux.Utils.EventQueue,{
  88. current_state : null,
  89. trans_table : null,
  90. trans_table_scope : null,
  91. /**
  92. * Returns current state
  93. *
  94. * @access public
  95. * @return mixed Current state.
  96. */
  97. state : function() {
  98. return this.current_state;
  99. },
  100. /**
  101. * @access public
  102. */
  103. processEvent : function(event, data) {
  104. var transitions = this.currentStateEventTransitions(event);
  105. if (!transitions) {
  106. throw "State '" + this.current_state + "' has no transition for event '" + event + "'.";
  107. }
  108. for (var i = 0, len = transitions.length; i < len; i++) {
  109. var transition = transitions[i];
  110. var predicate = transition.predicate || transition.p || true;
  111. var action = transition.action || transition.a || Ext.emptyFn;
  112. var new_state = transition.state || transition.s || this.current_state;
  113. var scope = transition.scope || this.trans_table_scope;
  114. if (this.computePredicate(predicate, scope, data, event)) {
  115. this.callAction(action, scope, data, event);
  116. this.current_state = new_state;
  117. return;
  118. }
  119. }
  120. throw "State '" + this.current_state + "' has no transition for event '" + event + "' in current context";
  121. },
  122. /**
  123. * @access private
  124. */
  125. currentStateEventTransitions : function(event) {
  126. return this.trans_table[this.current_state] ?
  127. this.trans_table[this.current_state][event] || false
  128. :
  129. false;
  130. },
  131. /**
  132. * @access private
  133. */
  134. computePredicate : function(predicate, scope, data, event) {
  135. var result = false;
  136. switch (Ext.type(predicate)) {
  137. case 'function':
  138. result = predicate.call(scope, data, event, this);
  139. break;
  140. case 'array':
  141. result = true;
  142. for (var i = 0, len = predicate.length; result && (i < len); i++) {
  143. if (Ext.type(predicate[i]) == 'function') {
  144. result = predicate[i].call(scope, data, event, this);
  145. }
  146. else {
  147. throw [
  148. 'Predicate: ',
  149. predicate[i],
  150. ' is not callable in "',
  151. this.current_state,
  152. '" state for event "',
  153. event
  154. ].join('');
  155. }
  156. }
  157. break;
  158. case 'boolean':
  159. result = predicate;
  160. break;
  161. default:
  162. throw [
  163. 'Predicate: ',
  164. predicate,
  165. ' is not callable in "',
  166. this.current_state,
  167. '" state for event "',
  168. event
  169. ].join('');
  170. }
  171. return result;
  172. },
  173. /**
  174. * @access private
  175. */
  176. callAction : function(action, scope, data, event)
  177. {
  178. switch (Ext.type(action)) {
  179. case 'array':
  180. for (var i = 0, len = action.length; i < len; i++) {
  181. if (Ext.type(action[i]) == 'function') {
  182. action[i].call(scope, data, event, this);
  183. }
  184. else {
  185. throw [
  186. 'Action: ',
  187. action[i],
  188. ' is not callable in "',
  189. this.current_state,
  190. '" state for event "',
  191. event
  192. ].join('');
  193. }
  194. }
  195. break;
  196. case 'function':
  197. action.call(scope, data, event, this);
  198. break;
  199. default:
  200. throw [
  201. 'Action: ',
  202. action,
  203. ' is not callable in "',
  204. this.current_state,
  205. '" state for event "',
  206. event
  207. ].join('');
  208. }
  209. }
  210. });
  211. // ---------------------------------------------------------------------------------------------- //
  212. /**
  213. * Ext.ux.UploadDialog namespace.
  214. */
  215. Ext.namespace('Ext.ux.UploadDialog');
  216. /**
  217. * File upload browse button.
  218. *
  219. * @class Ext.ux.UploadDialog.BrowseButton
  220. */
  221. Ext.ux.UploadDialog.BrowseButton = Ext.extend(Ext.Button,{
  222. input_name : 'file',
  223. input_file : null,
  224. original_handler : null,
  225. original_scope : null,
  226. /**
  227. * @access private
  228. */
  229. initComponent : function()
  230. {
  231. Ext.ux.UploadDialog.BrowseButton.superclass.initComponent.call(this);
  232. this.original_handler = this.handler || null;
  233. this.original_scope = this.scope || window;
  234. this.handler = null;
  235. this.scope = null;
  236. },
  237. /**
  238. * @access private
  239. */
  240. onRender : function(ct, position)
  241. {
  242. Ext.ux.UploadDialog.BrowseButton.superclass.onRender.call(this, ct, position);
  243. this.createInputFile();
  244. },
  245. /**
  246. * @access private
  247. */
  248. createInputFile : function()
  249. {
  250. var button_container = this.el;
  251. button_container.position('relative');
  252. this.wrap = this.el.wrap({cls:'tbody'});
  253. this.input_file = this.wrap.createChild({
  254. tag: 'input',
  255. type: 'file',
  256. size: 1,
  257. name: this.input_name || Ext.id(this.el),
  258. style: "position: absolute; display: block; border: none; cursor: pointer"
  259. });
  260. this.input_file.setOpacity(0.0);
  261. var button_box = button_container.getBox();
  262. this.input_file.setStyle('font-size', (button_box.width * 0.5) + 'px');
  263. var input_box = this.input_file.getBox();
  264. var adj = {x: 3, y: 3}
  265. if (Ext.isIE) {
  266. adj = {x: 0, y: 3}
  267. }
  268. this.input_file.setLeft(button_box.width - input_box.width + adj.x + 'px');
  269. this.input_file.setTop(button_box.height - input_box.height + adj.y + 'px');
  270. this.input_file.setOpacity(0.0);
  271. if (this.handleMouseEvents) {
  272. this.input_file.on('mouseover', this.onMouseOver, this);
  273. this.input_file.on('mousedown', this.onMouseDown, this);
  274. }
  275. if(this.tooltip){
  276. if(typeof this.tooltip == 'object'){
  277. Ext.QuickTips.register(Ext.apply({target: this.input_file}, this.tooltip));
  278. }
  279. else {
  280. this.input_file.dom[this.tooltipType] = this.tooltip;
  281. }
  282. }
  283. this.input_file.on('change', this.onInputFileChange, this);
  284. this.input_file.on('click', function(e) { e.stopPropagation(); });
  285. },
  286. /**
  287. * @access public
  288. */
  289. detachInputFile : function(no_create)
  290. {
  291. var result = this.input_file;
  292. no_create = no_create || false;
  293. if (typeof this.tooltip == 'object') {
  294. Ext.QuickTips.unregister(this.input_file);
  295. }
  296. else {
  297. this.input_file.dom[this.tooltipType] = null;
  298. }
  299. this.input_file.removeAllListeners();
  300. this.input_file = null;
  301. if (!no_create) {
  302. this.createInputFile();
  303. }
  304. return result;
  305. },
  306. /**
  307. * @access public
  308. */
  309. getInputFile : function()
  310. {
  311. return this.input_file;
  312. },
  313. /**
  314. * @access public
  315. */
  316. disable : function()
  317. {
  318. Ext.ux.UploadDialog.BrowseButton.superclass.disable.call(this);
  319. this.input_file.dom.disabled = true;
  320. },
  321. /**
  322. * @access public
  323. */
  324. enable : function()
  325. {
  326. Ext.ux.UploadDialog.BrowseButton.superclass.enable.call(this);
  327. this.input_file.dom.disabled = false;
  328. },
  329. /**
  330. * @access public
  331. */
  332. destroy : function()
  333. {
  334. var input_file = this.detachInputFile(true);
  335. input_file.remove();
  336. input_file = null;
  337. Ext.ux.UploadDialog.BrowseButton.superclass.destroy.call(this);
  338. },
  339. /**
  340. * @access private
  341. */
  342. onInputFileChange : function()
  343. {
  344. if (this.original_handler) {
  345. this.original_handler.call(this.original_scope, this);
  346. }
  347. }
  348. });
  349. /**
  350. * Toolbar file upload browse button.
  351. *
  352. * @class Ext.ux.UploadDialog.TBBrowseButton
  353. */
  354. Ext.ux.UploadDialog.TBBrowseButton = Ext.extend(Ext.ux.UploadDialog.BrowseButton,{
  355. hideParent : true
  356. ,onDestroy : function() {
  357. Ext.ux.UploadDialog.TBBrowseButton.superclass.onDestroy.call(this);
  358. if(this.container) {
  359. this.container.remove();
  360. }
  361. }
  362. });
  363. /**
  364. * Record type for dialogs grid.
  365. *
  366. * @class Ext.ux.UploadDialog.FileRecord
  367. */
  368. Ext.ux.UploadDialog.FileRecord = Ext.data.Record.create([
  369. {name: 'filename'},
  370. {name: 'state', type: 'int'},
  371. {name: 'note'},
  372. {name: 'input_element'}
  373. ]);
  374. Ext.ux.UploadDialog.FileRecord.STATE_QUEUE = 0;
  375. Ext.ux.UploadDialog.FileRecord.STATE_FINISHED = 1;
  376. Ext.ux.UploadDialog.FileRecord.STATE_FAILED = 2;
  377. Ext.ux.UploadDialog.FileRecord.STATE_PROCESSING = 3;
  378. /**
  379. * Dialog class.
  380. *
  381. * @class Ext.ux.UploadDialog.Dialog
  382. */
  383. Ext.ux.UploadDialog.Dialog = function(config) {
  384. var default_config = {
  385. border: false,
  386. width: 600,
  387. height: 350,
  388. // minWidth: 450,
  389. minHeight: 350,
  390. plain: true,
  391. constrainHeader: true,
  392. draggable: true,
  393. closable: true,
  394. maximizable: false,
  395. minimizable: false,
  396. resizable: true,
  397. layout:'fit',
  398. region:'center',
  399. autoDestroy: true,
  400. closeAction: 'hide',
  401. title: this.i18n.title,
  402. cls: 'ext-ux-uploaddialog-dialog',
  403. // --------
  404. url: '',
  405. base_params: {},
  406. permitted_extensions: [],
  407. reset_on_hide: true,
  408. allow_close_on_upload: false,
  409. upload_autostart: false,
  410. Make_Reload: false,
  411. post_var_name: 'file'
  412. };
  413. config = Ext.applyIf(config || {}, default_config);
  414. config.layout = 'absolute';
  415. Ext.ux.UploadDialog.Dialog.superclass.constructor.call(this, config);
  416. };
  417. Ext.extend(Ext.ux.UploadDialog.Dialog, Ext.Window,{
  418. fsa : null,
  419. state_tpl : null,
  420. form : null,
  421. grid_panel : null,
  422. progress_bar : null,
  423. is_uploading : false,
  424. initial_queued_count : 0,
  425. upload_frame : null,
  426. /**
  427. * @access private
  428. */
  429. //--------------------------------------------------------------------------------------------- //
  430. initComponent : function() {
  431. Ext.ux.UploadDialog.Dialog.superclass.initComponent.call(this);
  432. // Setting automata protocol
  433. var tt = {
  434. // --------------
  435. 'created' : {
  436. // --------------
  437. 'window-render' : [
  438. {
  439. action: [this.createForm, this.createProgressBar, this.createGrid],
  440. state: 'rendering'
  441. }
  442. ],
  443. 'destroy' : [
  444. {
  445. action: this.flushEventQueue,
  446. state: 'destroyed'
  447. }
  448. ]
  449. },
  450. // --------------
  451. 'rendering' : {
  452. // --------------
  453. 'grid-render' : [
  454. {
  455. action: [this.fillToolbar, this.updateToolbar],
  456. state: 'ready'
  457. }
  458. ],
  459. 'destroy' : [
  460. {
  461. action: this.flushEventQueue,
  462. state: 'destroyed'
  463. }
  464. ]
  465. },
  466. // --------------
  467. 'ready' : {
  468. // --------------
  469. 'file-selected' : [
  470. {
  471. predicate: [this.fireFileTestEvent, this.isPermittedFile],
  472. action: this.addFileToUploadQueue,
  473. state: 'adding-file'
  474. },
  475. {
  476. // If file is not permitted then do nothing.
  477. }
  478. ],
  479. 'grid-selection-change' : [
  480. {
  481. action: this.updateToolbar
  482. }
  483. ],
  484. 'remove-files' : [
  485. {
  486. action: [this.removeFiles, this.fireFileRemoveEvent]
  487. }
  488. ],
  489. 'reset-queue' : [
  490. {
  491. action: [this.resetQueue, this.fireResetQueueEvent]
  492. }
  493. ],
  494. 'start-upload' : [
  495. {
  496. predicate: this.hasUnuploadedFiles,
  497. action: [
  498. this.setUploadingFlag, this.saveInitialQueuedCount, this.updateToolbar,
  499. this.updateProgressBar, this.prepareNextUploadTask, this.fireUploadStartEvent
  500. ],
  501. state: 'uploading'
  502. },
  503. {
  504. // Has nothing to upload, do nothing.
  505. }
  506. ],
  507. 'stop-upload' : [
  508. {
  509. // We are not uploading, do nothing. Can be posted by user only at this state.
  510. }
  511. ],
  512. 'hide' : [
  513. {
  514. predicate: [this.isNotEmptyQueue, this.getResetOnHide],
  515. action: [this.resetQueue, this.fireResetQueueEvent]
  516. },
  517. {
  518. // Do nothing
  519. }
  520. ],
  521. 'destroy' : [
  522. {
  523. action: this.flushEventQueue,
  524. state: 'destroyed'
  525. }
  526. ]
  527. },
  528. // --------------
  529. 'adding-file' : {
  530. // --------------
  531. 'file-added' : [
  532. {
  533. predicate: this.isUploading,
  534. action: [this.incInitialQueuedCount, this.updateProgressBar, this.fireFileAddEvent],
  535. state: 'uploading'
  536. },
  537. {
  538. predicate: this.getUploadAutostart,
  539. action: [this.startUpload, this.fireFileAddEvent],
  540. state: 'ready'
  541. },
  542. {
  543. action: [this.updateToolbar, this.fireFileAddEvent],
  544. state: 'ready'
  545. }
  546. ]
  547. },
  548. // --------------
  549. 'uploading' : {
  550. // --------------
  551. 'file-selected' : [
  552. {
  553. predicate: [this.fireFileTestEvent, this.isPermittedFile],
  554. action: this.addFileToUploadQueue,
  555. state: 'adding-file'
  556. },
  557. {
  558. // If file is not permitted then do nothing.
  559. }
  560. ],
  561. 'grid-selection-change' : [
  562. {
  563. // Do nothing.
  564. }
  565. ],
  566. 'start-upload' : [
  567. {
  568. // Can be posted only by user in this state.
  569. }
  570. ],
  571. 'stop-upload' : [
  572. {
  573. predicate: this.hasUnuploadedFiles,
  574. action: [
  575. this.resetUploadingFlag, this.abortUpload, this.updateToolbar,
  576. this.updateProgressBar, this.fireUploadStopEvent
  577. ],
  578. state: 'ready'
  579. },
  580. {
  581. action: [
  582. this.resetUploadingFlag, this.abortUpload, this.updateToolbar,
  583. this.updateProgressBar, this.fireUploadStopEvent, this.fireUploadCompleteEvent
  584. ],
  585. state: 'ready'
  586. }
  587. ],
  588. 'file-upload-start' : [
  589. {
  590. action: [this.uploadFile, this.findUploadFrame, this.fireFileUploadStartEvent]
  591. }
  592. ],
  593. 'file-upload-success' : [
  594. {
  595. predicate: this.hasUnuploadedFiles,
  596. action: [
  597. this.resetUploadFrame, this.updateRecordState, this.updateProgressBar,
  598. this.prepareNextUploadTask, this.fireUploadSuccessEvent
  599. ]
  600. },
  601. {
  602. action: [
  603. this.resetUploadFrame, this.resetUploadingFlag, this.updateRecordState,
  604. this.updateToolbar, this.updateProgressBar, this.fireUploadSuccessEvent,
  605. this.fireUploadCompleteEvent
  606. ],
  607. state: 'ready'
  608. }
  609. ],
  610. 'file-upload-error' : [
  611. {
  612. predicate: this.hasUnuploadedFiles,
  613. action: [
  614. this.resetUploadFrame, this.updateRecordState, this.updateProgressBar,
  615. this.prepareNextUploadTask, this.fireUploadErrorEvent
  616. ]
  617. },
  618. {
  619. action: [
  620. this.resetUploadFrame, this.resetUploadingFlag, this.updateRecordState,
  621. this.updateToolbar, this.updateProgressBar, this.fireUploadErrorEvent,
  622. this.fireUploadCompleteEvent
  623. ],
  624. state: 'ready'
  625. }
  626. ],
  627. 'file-upload-failed' : [
  628. {
  629. predicate: this.hasUnuploadedFiles,
  630. action: [
  631. this.resetUploadFrame, this.updateRecordState, this.updateProgressBar,
  632. this.prepareNextUploadTask, this.fireUploadFailedEvent
  633. ]
  634. },
  635. {
  636. action: [
  637. this.resetUploadFrame, this.resetUploadingFlag, this.updateRecordState,
  638. this.updateToolbar, this.updateProgressBar, this.fireUploadFailedEvent,
  639. this.fireUploadCompleteEvent
  640. ],
  641. state: 'ready'
  642. }
  643. ],
  644. 'hide' : [
  645. {
  646. predicate: this.getResetOnHide,
  647. action: [this.stopUpload, this.repostHide]
  648. },
  649. {
  650. // Do nothing.
  651. }
  652. ],
  653. 'destroy' : [
  654. {
  655. predicate: this.hasUnuploadedFiles,
  656. action: [
  657. this.resetUploadingFlag, this.abortUpload,
  658. this.fireUploadStopEvent, this.flushEventQueue
  659. ],
  660. state: 'destroyed'
  661. },
  662. {
  663. action: [
  664. this.resetUploadingFlag, this.abortUpload,
  665. this.fireUploadStopEvent, this.fireUploadCompleteEvent, this.flushEventQueue
  666. ],
  667. state: 'destroyed'
  668. }
  669. ]
  670. },
  671. // --------------
  672. 'destroyed' : {
  673. // --------------
  674. }
  675. };
  676. this.fsa = new Ext.ux.Utils.FSA('created', tt, this);
  677. // Registering dialog events.
  678. this.addEvents({
  679. 'filetest': true
  680. ,'fileadd' : true
  681. ,'fileremove' : true
  682. ,'resetqueue' : true
  683. ,'uploadsuccess' : true
  684. ,'uploaderror' : true
  685. ,'uploadfailed' : true
  686. ,'uploadstart' : true
  687. ,'uploadstop' : true
  688. ,'uploadcomplete' : true
  689. ,'fileuploadstart' : true
  690. });
  691. // Attaching to window events.
  692. this.on('render', this.onWindowRender, this);
  693. this.on('beforehide', this.onWindowBeforeHide, this);
  694. this.on('hide', this.onWindowHide, this);
  695. this.on('destroy', this.onWindowDestroy, this);
  696. // Compiling state template.
  697. this.state_tpl = new Ext.Template(
  698. "<div class='ext-ux-uploaddialog-state ext-ux-uploaddialog-state-{state}'> </div>"
  699. ).compile();
  700. },
  701. createForm : function()
  702. {
  703. this.form = Ext.DomHelper.append(this.body, {
  704. tag: 'form',
  705. method: 'post',
  706. action: this.url,
  707. style: 'position: absolute; left: -100px; top: -100px; width: 100px; height: 100px; clear: both;'
  708. });
  709. },
  710. createProgressBar : function()
  711. {
  712. this.progress_bar = this.add(
  713. new Ext.ProgressBar({
  714. x: 0,
  715. y: 0,
  716. anchor: '0',
  717. value: 0.0,
  718. text: this.i18n.progress_waiting_text
  719. })
  720. );
  721. },
  722. createGrid : function()
  723. {
  724. var store = new Ext.data.Store({
  725. proxy: new Ext.data.MemoryProxy([]),
  726. reader: new Ext.data.JsonReader({}, Ext.ux.UploadDialog.FileRecord),
  727. sortInfo: {field: 'state', direction: 'DESC'},
  728. pruneModifiedRecords: true
  729. });
  730. var cm = new Ext.grid.ColumnModel([
  731. {
  732. header: this.i18n.state_col_title,
  733. width: this.i18n.state_col_width,
  734. resizable: false,
  735. dataIndex: 'state',
  736. sortable: true,
  737. renderer: this.renderStateCell.createDelegate(this)
  738. },
  739. {
  740. header: this.i18n.filename_col_title,
  741. width: this.i18n.filename_col_width,
  742. dataIndex: 'filename',
  743. sortable: true,
  744. renderer: this.renderFilenameCell.createDelegate(this)
  745. },
  746. {
  747. header: this.i18n.note_col_title,
  748. width: this.i18n.note_col_width,
  749. dataIndex: 'note',
  750. sortable: true,
  751. renderer: this.renderNoteCell.createDelegate(this)
  752. }
  753. ]);
  754. this.grid_panel = new Ext.grid.GridPanel({
  755. ds: store,
  756. cm: cm,
  757. layout:'fit',
  758. height: this.height-100,
  759. region:'center',
  760. x: 0,
  761. y: 22,
  762. border: true,
  763. viewConfig: {
  764. autoFill: true,
  765. forceFit: true
  766. },
  767. bbar : new Ext.Toolbar()
  768. });
  769. this.grid_panel.on('render', this.onGridRender, this);
  770. this.add(this.grid_panel);
  771. this.grid_panel.getSelectionModel().on('selectionchange', this.onGridSelectionChange, this);
  772. },
  773. fillToolbar : function()
  774. {
  775. var tb = this.grid_panel.getBottomToolbar();
  776. tb.x_buttons = {}
  777. tb.x_buttons.add = tb.addItem(new Ext.ux.UploadDialog.TBBrowseButton({
  778. input_name: this.post_var_name,
  779. text: this.i18n.add_btn_text,
  780. tooltip: this.i18n.add_btn_tip,
  781. iconCls: 'ext-ux-uploaddialog-addbtn',
  782. handler: this.onAddButtonFileSelected,
  783. scope: this
  784. }));
  785. tb.x_buttons.remove = tb.addButton({
  786. text: this.i18n.remove_btn_text,
  787. tooltip: this.i18n.remove_btn_tip,
  788. iconCls: 'ext-ux-uploaddialog-removebtn',
  789. handler: this.onRemoveButtonClick,
  790. scope: this
  791. });
  792. tb.x_buttons.reset = tb.addButton({
  793. text: this.i18n.reset_btn_text,
  794. tooltip: this.i18n.reset_btn_tip,
  795. iconCls: 'ext-ux-uploaddialog-resetbtn',
  796. handler: this.onResetButtonClick,
  797. scope: this
  798. });
  799. tb.x_buttons.upload = tb.addButton({
  800. text: this.i18n.upload_btn_start_text,
  801. tooltip: this.i18n.upload_btn_start_tip,
  802. iconCls: 'ext-ux-uploaddialog-uploadstartbtn',
  803. handler: this.onUploadButtonClick,
  804. scope: this
  805. });
  806. tb.x_buttons.close = tb.addButton({
  807. text: this.i18n.close_btn_text,
  808. tooltip: this.i18n.close_btn_tip,
  809. handler: this.onCloseButtonClick,
  810. scope: this
  811. });
  812. },
  813. renderStateCell : function(data, cell, record, row_index, column_index, store)
  814. {
  815. return this.state_tpl.apply({state: data});
  816. },
  817. renderFilenameCell : function(data, cell, record, row_index, column_index, store)
  818. {
  819. var view = this.grid_panel.getView();
  820. var f = function() {
  821. try {
  822. Ext.fly(
  823. view.getCell(row_index, column_index)
  824. ).child('.x-grid3-cell-inner').dom['qtip'] = data;
  825. }
  826. catch (e)
  827. {}
  828. }
  829. f.defer(1000);
  830. return data;
  831. },
  832. renderNoteCell : function(data, cell, record, row_index, column_index, store)
  833. {
  834. var view = this.grid_panel.getView();
  835. var f = function() {
  836. try {
  837. Ext.fly(
  838. view.getCell(row_index, column_index)
  839. ).child('.x-grid3-cell-inner').dom['qtip'] = data;
  840. }
  841. catch (e)
  842. {}
  843. }
  844. f.defer(1000);
  845. return data;
  846. },
  847. getFileExtension : function(filename)
  848. {
  849. var result = null;
  850. var parts = filename.split('.');
  851. if (parts.length > 1) {
  852. result = parts.pop();
  853. }
  854. return result;
  855. },
  856. isPermittedFileType : function(filename)
  857. {
  858. var result = true;
  859. if (this.permitted_extensions.length > 0) {
  860. result = this.permitted_extensions.indexOf(this.getFileExtension(filename)) != -1;
  861. }
  862. return result;
  863. },
  864. isPermittedFile : function(browse_btn)
  865. {
  866. var result = false;
  867. var filename = browse_btn.getInputFile().dom.value;
  868. if (this.isPermittedFileType(filename)) {
  869. result = true;
  870. }
  871. else {
  872. Ext.Msg.alert(
  873. this.i18n.error_msgbox_title,
  874. String.format(
  875. this.i18n.err_file_type_not_permitted,
  876. filename,
  877. this.permitted_extensions.join(this.i18n.permitted_extensions_join_str)
  878. )
  879. );
  880. result = false;
  881. }
  882. return result;
  883. },
  884. fireFileTestEvent : function(browse_btn)
  885. {
  886. return this.fireEvent('filetest', this, browse_btn.getInputFile().dom.value) !== false;
  887. },
  888. addFileToUploadQueue : function(browse_btn)
  889. {
  890. var input_file = browse_btn.detachInputFile();
  891. input_file.appendTo(this.form);
  892. input_file.setStyle('width', '100px');
  893. input_file.dom.disabled = true;
  894. var store = this.grid_panel.getStore();
  895. var fileApi = input_file.dom.files;
  896. var filename = (typeof fileApi != 'undefined') ? fileApi[0].name : input_file.dom.value.replace("C:\\fakepath\\", "");
  897. store.add(new Ext.ux.UploadDialog.FileRecord({
  898. state: Ext.ux.UploadDialog.FileRecord.STATE_QUEUE
  899. ,filename: filename
  900. ,note: this.i18n.note_queued_to_upload
  901. ,input_element: input_file
  902. }));
  903. this.fsa.postEvent('file-added', input_file.dom.value);
  904. },
  905. fireFileAddEvent : function(filename)
  906. {
  907. this.fireEvent('fileadd', this, filename);
  908. },
  909. updateProgressBar : function()
  910. {
  911. if (this.is_uploading) {
  912. var queued = this.getQueuedCount(true);
  913. var value = 1 - queued / this.initial_queued_count;
  914. this.progress_bar.updateProgress(value,String.format(this.i18n.progress_uploading_text,this.initial_queued_count - queued,this.initial_queued_count));
  915. }
  916. else {
  917. this.progress_bar.updateProgress(0, this.i18n.progress_waiting_text);
  918. }
  919. },
  920. updateToolbar : function() {
  921. var tb = this.grid_panel.getBottomToolbar();
  922. if (this.is_uploading) {
  923. tb.x_buttons.remove.disable();
  924. tb.x_buttons.reset.disable();
  925. tb.x_buttons.upload.enable();
  926. if (!this.getAllowCloseOnUpload()) {
  927. tb.x_buttons.close.disable();
  928. }
  929. tb.x_buttons.upload.setIconClass('ext-ux-uploaddialog-uploadstopbtn');
  930. tb.x_buttons.upload.setText(this.i18n.upload_btn_stop_text);
  931. tb.x_buttons.upload.getEl()
  932. .child(tb.x_buttons.upload.buttonSelector)
  933. .dom[tb.x_buttons.upload.tooltipType] = this.i18n.upload_btn_stop_tip;
  934. }
  935. else {
  936. tb.x_buttons.remove.enable();
  937. tb.x_buttons.reset.enable();
  938. tb.x_buttons.close.enable();
  939. tb.x_buttons.upload.setIconClass('ext-ux-uploaddialog-uploadstartbtn');
  940. tb.x_buttons.upload.setText(this.i18n.upload_btn_start_text);
  941. if (this.getQueuedCount() > 0) {
  942. tb.x_buttons.upload.enable();
  943. }
  944. else {
  945. tb.x_buttons.upload.disable();
  946. }
  947. if (this.grid_panel.getSelectionModel().hasSelection()) {
  948. tb.x_buttons.remove.enable();
  949. }
  950. else {
  951. tb.x_buttons.remove.disable();
  952. }
  953. if (this.grid_panel.getStore().getCount() > 0) {
  954. tb.x_buttons.reset.enable();
  955. }
  956. else {
  957. tb.x_buttons.reset.disable();
  958. }
  959. }
  960. },
  961. saveInitialQueuedCount : function()
  962. {
  963. this.initial_queued_count = this.getQueuedCount();
  964. },
  965. incInitialQueuedCount : function()
  966. {
  967. this.initial_queued_count++;
  968. },
  969. setUploadingFlag : function()
  970. {
  971. this.is_uploading = true;
  972. },
  973. resetUploadingFlag : function()
  974. {
  975. this.is_uploading = false;
  976. },
  977. prepareNextUploadTask : function()
  978. {
  979. // Searching for first unuploaded file.
  980. var store = this.grid_panel.getStore();
  981. var record = null;
  982. store.each(function(r) {
  983. if (!record && r.get('state') == Ext.ux.UploadDialog.FileRecord.STATE_QUEUE) {
  984. record = r;
  985. }
  986. else {
  987. r.get('input_element').dom.disabled = true;
  988. }
  989. });
  990. record.get('input_element').dom.disabled = false;
  991. record.set('state', Ext.ux.UploadDialog.FileRecord.STATE_PROCESSING);
  992. record.set('note', this.i18n.note_processing);
  993. record.commit();
  994. this.fsa.postEvent('file-upload-start', record);
  995. },
  996. fireUploadStartEvent : function()
  997. {
  998. this.fireEvent('uploadstart', this);
  999. },
  1000. removeFiles : function(file_records)
  1001. {
  1002. var store = this.grid_panel.getStore();
  1003. for (var i = 0, len = file_records.length; i < len; i++) {
  1004. var r = file_records[i];
  1005. r.get('input_element').remove();
  1006. store.remove(r);
  1007. }
  1008. },
  1009. fireFileRemoveEvent : function(file_records)
  1010. {
  1011. for (var i = 0, len = file_records.length; i < len; i++) {
  1012. this.fireEvent('fileremove', this, file_records[i].get('filename'));
  1013. }
  1014. },
  1015. resetQueue : function() {
  1016. var store = this.grid_panel.getStore();
  1017. store.each(function(r) {
  1018. r.get('input_element').remove();
  1019. });
  1020. store.removeAll();
  1021. },
  1022. fireResetQueueEvent : function() {
  1023. this.fireEvent('resetqueue', this);
  1024. }
  1025. ,uploadFile : function(record) {
  1026. Ext.Ajax.request({
  1027. url: this.url
  1028. ,params: this.base_params || this.baseParams || this.params
  1029. ,method: 'POST'
  1030. ,form: this.form
  1031. ,isUpload: true
  1032. ,success: this.onAjaxSuccess
  1033. ,failure: this.onAjaxFailure
  1034. ,scope: this
  1035. ,record: record
  1036. });
  1037. },
  1038. fireFileUploadStartEvent : function(record)
  1039. {
  1040. this.fireEvent('fileuploadstart', this, record.get('filename'));
  1041. },
  1042. updateRecordState : function(data)
  1043. {
  1044. if ('success' in data.response && data.response.success) {
  1045. data.record.set('state', Ext.ux.UploadDialog.FileRecord.STATE_FINISHED);
  1046. data.record.set(
  1047. 'note', data.response.message || data.response.error || this.i18n.note_upload_success
  1048. );
  1049. }
  1050. else {
  1051. data.record.set('state', Ext.ux.UploadDialog.FileRecord.STATE_FAILED);
  1052. data.record.set(
  1053. 'note', data.response.message || data.response.error || this.i18n.note_upload_error
  1054. );
  1055. }
  1056. data.record.commit();
  1057. },
  1058. fireUploadSuccessEvent : function(data)
  1059. {
  1060. this.fireEvent('uploadsuccess', this, data.record.get('filename'), data.response);
  1061. },
  1062. fireUploadErrorEvent : function(data)
  1063. {
  1064. this.fireEvent('uploaderror', this, data.record.get('filename'), data.response);
  1065. },
  1066. fireUploadFailedEvent : function(data)
  1067. {
  1068. this.fireEvent('uploadfailed', this, data.record.get('filename'));
  1069. },
  1070. fireUploadCompleteEvent : function()
  1071. {
  1072. this.fireEvent('uploadcomplete', this);
  1073. },
  1074. findUploadFrame : function()
  1075. {
  1076. this.upload_frame = Ext.getBody().child('iframe.x-hidden:last');
  1077. },
  1078. resetUploadFrame : function()
  1079. {
  1080. this.upload_frame = null;
  1081. },
  1082. removeUploadFrame : function()
  1083. {
  1084. if (this.upload_frame) {
  1085. this.upload_frame.removeAllListeners();
  1086. this.upload_frame.dom.src = 'about:blank';
  1087. this.upload_frame.remove();
  1088. }
  1089. this.upload_frame = null;
  1090. },
  1091. abortUpload : function()
  1092. {
  1093. this.removeUploadFrame();
  1094. var store = this.grid_panel.getStore();
  1095. var record = null;
  1096. store.each(function(r) {
  1097. if (r.get('state') == Ext.ux.UploadDialog.FileRecord.STATE_PROCESSING) {
  1098. record = r;
  1099. return false;
  1100. }
  1101. });
  1102. record.set('state', Ext.ux.UploadDialog.FileRecord.STATE_FAILED);
  1103. record.set('note', this.i18n.note_aborted);
  1104. record.commit();
  1105. },
  1106. fireUploadStopEvent : function()
  1107. {
  1108. this.fireEvent('uploadstop', this);
  1109. },
  1110. repostHide : function()
  1111. {
  1112. this.fsa.postEvent('hide');
  1113. },
  1114. flushEventQueue : function()
  1115. {
  1116. this.fsa.flushEventQueue();
  1117. },
  1118. /**
  1119. * @access private
  1120. */
  1121. // -------------------------------------------------------------------------------------------- //
  1122. onWindowRender : function()
  1123. {
  1124. this.fsa.postEvent('window-render');
  1125. },
  1126. onWindowBeforeHide : function()
  1127. {
  1128. return this.isUploading() ? this.getAllowCloseOnUpload() : true;
  1129. },
  1130. onWindowHide : function()
  1131. {
  1132. this.fsa.postEvent('hide');
  1133. },
  1134. onWindowDestroy : function()
  1135. {
  1136. this.fsa.postEvent('destroy');
  1137. },
  1138. onGridRender : function()
  1139. {
  1140. this.fsa.postEvent('grid-render');
  1141. },
  1142. onGridSelectionChange : function()
  1143. {
  1144. this.fsa.postEvent('grid-selection-change');
  1145. },
  1146. onAddButtonFileSelected : function(btn)
  1147. {
  1148. this.fsa.postEvent('file-selected', btn);
  1149. },
  1150. onUploadButtonClick : function()
  1151. {
  1152. if (this.is_uploading) {
  1153. this.fsa.postEvent('stop-upload');
  1154. }
  1155. else {
  1156. this.fsa.postEvent('start-upload');
  1157. }
  1158. },
  1159. onRemoveButtonClick : function()
  1160. {
  1161. var selections = this.grid_panel.getSelectionModel().getSelections();
  1162. this.fsa.postEvent('remove-files', selections);
  1163. },
  1164. onResetButtonClick : function()
  1165. {
  1166. this.fsa.postEvent('reset-queue');
  1167. },
  1168. onCloseButtonClick : function()
  1169. {
  1170. this[this.closeAction].call(this);
  1171. if(this.Make_Reload == true){
  1172. document.location.reload();
  1173. }
  1174. },
  1175. onAjaxSuccess : function(response, options) {
  1176. var json_response = {
  1177. 'success' : false,
  1178. 'error' : this.i18n.note_upload_error
  1179. }
  1180. try {
  1181. var rt = response.responseText;
  1182. var filter = rt.match(/^<pre>((?:.|\n)*)<\/pre>$/i);
  1183. if (filter) {
  1184. rt = filter[1];
  1185. }
  1186. json_response = Ext.util.JSON.decode(rt);
  1187. }
  1188. catch (e) {}
  1189. var data = {
  1190. record: options.record,
  1191. response: json_response
  1192. }
  1193. if ('success' in json_response && json_response.success) {
  1194. this.fsa.postEvent('file-upload-success', data);
  1195. }
  1196. else {
  1197. this.fsa.postEvent('file-upload-error', data);
  1198. }
  1199. },
  1200. onAjaxFailure : function(response, options)
  1201. {
  1202. var data = {
  1203. record : options.record,
  1204. response : {
  1205. 'success' : false,
  1206. 'error' : this.i18n.note_upload_failed
  1207. }
  1208. }
  1209. this.fsa.postEvent('file-upload-failed', data);
  1210. },
  1211. /**
  1212. * @access public
  1213. */
  1214. // -------------------------------------------------------------------------------------------- //
  1215. startUpload : function()
  1216. {
  1217. this.fsa.postEvent('start-upload');
  1218. },
  1219. stopUpload : function()
  1220. {
  1221. this.fsa.postEvent('stop-upload');
  1222. },
  1223. getUrl : function()
  1224. {
  1225. return this.url;
  1226. },
  1227. setUrl : function(url)
  1228. {
  1229. this.url = url;
  1230. },
  1231. getBaseParams : function()
  1232. {
  1233. return this.base_params;
  1234. },
  1235. setBaseParams : function(params)
  1236. {
  1237. this.base_params = params;
  1238. },
  1239. getUploadAutostart : function()
  1240. {
  1241. return this.upload_autostart;
  1242. },
  1243. setUploadAutostart : function(value)
  1244. {
  1245. this.upload_autostart = value;
  1246. },
  1247. ///////////EIGENE ERWEITERUNG RELOAD EXT//////////////////////
  1248. getMakeReload : function()
  1249. {
  1250. return this.Make_Reload;
  1251. },
  1252. setMakeReload : function(value)
  1253. {
  1254. this.Make_Reload = value;
  1255. }
  1256. ///////////EIGENE ERWEITERUNG RELOAD EXT//////////////////////
  1257. ,getAllowCloseOnUpload : function() {
  1258. return this.allow_close_on_upload;
  1259. }
  1260. ,setAllowCloseOnUpload : function(value) {
  1261. this.allow_close_on_upload;
  1262. }
  1263. ,getResetOnHide : function() {
  1264. return this.reset_on_hide;
  1265. }
  1266. ,setResetOnHide : function(value) {
  1267. this.reset_on_hide = value;
  1268. }
  1269. ,getPermittedExtensions : function() {
  1270. return this.permitted_extensions;
  1271. }
  1272. ,setPermittedExtensions : function(value) {
  1273. this.permitted_extensions = value;
  1274. }
  1275. ,isUploading : function() {
  1276. return this.is_uploading;
  1277. }
  1278. ,isNotEmptyQueue : function() {
  1279. return this.grid_panel.getStore().getCount() > 0;
  1280. }
  1281. ,getQueuedCount : function(count_processing) {
  1282. var count = 0;
  1283. var store = this.grid_panel.getStore();
  1284. store.each(function(r) {
  1285. if (r.get('state') == Ext.ux.UploadDialog.FileRecord.STATE_QUEUE) {
  1286. count++;
  1287. }
  1288. if (count_processing && r.get('state') == Ext.ux.UploadDialog.FileRecord.STATE_PROCESSING) {
  1289. count++;
  1290. }
  1291. });
  1292. return count;
  1293. }
  1294. ,hasUnuploadedFiles : function() {
  1295. return this.getQueuedCount() > 0;
  1296. }
  1297. });
  1298. // ---------------------------------------------------------------------------------------------- //
  1299. var p = Ext.ux.UploadDialog.Dialog.prototype;
  1300. p.i18n = {
  1301. title: _('upload_files')
  1302. ,state_col_title: _('upf_state')
  1303. ,state_col_width: 70
  1304. ,filename_col_title: _('upf_filename')
  1305. ,filename_col_width: 230
  1306. ,note_col_title: _('upf_note')
  1307. ,note_col_width: 150
  1308. ,add_btn_text: _('upf_add')
  1309. ,add_btn_tip: _('upf_add_desc')
  1310. ,remove_btn_text: _('upf_remove')
  1311. ,remove_btn_tip: _('upf_remove_desc')
  1312. ,reset_btn_text: _('upf_reset')
  1313. ,reset_btn_tip: _('upf_reset_desc')
  1314. ,upload_btn_start_text: _('upf_upload')
  1315. ,upload_btn_start_tip: _('upf_upload_desc')
  1316. ,upload_btn_stop_text: _('upf_abort')
  1317. ,upload_btn_stop_tip: _('upf_abort_desc')
  1318. ,close_btn_text: _('upf_close')
  1319. ,close_btn_tip: _('upf_close_desc')
  1320. ,progress_waiting_text: _('upf_progress_wait')
  1321. ,progress_uploading_text: _('upf_uploading_desc')
  1322. ,error_msgbox_title: _('upf_error')
  1323. ,permitted_extensions_join_str: ','
  1324. ,err_file_type_not_permitted: _('upf_err_filetype')
  1325. ,note_queued_to_upload: _('upf_queued')
  1326. ,note_processing: _('upf_uploading')
  1327. ,note_upload_failed: _('upf_err_failed')
  1328. ,note_upload_success: _('upf_success')
  1329. ,note_upload_error: _('upf_upload_err')
  1330. ,note_aborted: _('upf_aborted')
  1331. };