Roo/bootstrap/DocumentManager.js
[roojs1] / Roo / bootstrap / DocumentManager.js
1
2 /*
3 * Licence: LGPL
4 */
5
6 /**
7  * @class Roo.bootstrap.DocumentManager
8  * @extends Roo.bootstrap.Component
9  * Bootstrap DocumentManager class
10  * @cfg {String} paramName default 'imageUpload'
11  * @cfg {String} method default POST
12  * @cfg {String} url action url
13  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
14  * @cfg {Boolean} multiple multiple upload default true
15  * @cfg {Number} thumbSize default 300
16  * @cfg {String} fieldLabel
17  * @cfg {Number} labelWidth default 4
18  * @cfg {String} labelAlign (left|top) default left
19  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
20  * 
21  * @constructor
22  * Create a new DocumentManager
23  * @param {Object} config The config object
24  */
25
26 Roo.bootstrap.DocumentManager = function(config){
27     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28     
29     this.files = [];
30     this.delegates = [];
31     
32     this.addEvents({
33         /**
34          * @event initial
35          * Fire when initial the DocumentManager
36          * @param {Roo.bootstrap.DocumentManager} this
37          */
38         "initial" : true,
39         /**
40          * @event inspect
41          * inspect selected file
42          * @param {Roo.bootstrap.DocumentManager} this
43          * @param {File} file
44          */
45         "inspect" : true,
46         /**
47          * @event exception
48          * Fire when xhr load exception
49          * @param {Roo.bootstrap.DocumentManager} this
50          * @param {XMLHttpRequest} xhr
51          */
52         "exception" : true,
53         /**
54          * @event afterupload
55          * Fire when xhr load exception
56          * @param {Roo.bootstrap.DocumentManager} this
57          * @param {XMLHttpRequest} xhr
58          */
59         "afterupload" : true,
60         /**
61          * @event prepare
62          * prepare the form data
63          * @param {Roo.bootstrap.DocumentManager} this
64          * @param {Object} formData
65          */
66         "prepare" : true,
67         /**
68          * @event remove
69          * Fire when remove the file
70          * @param {Roo.bootstrap.DocumentManager} this
71          * @param {Object} file
72          */
73         "remove" : true,
74         /**
75          * @event refresh
76          * Fire after refresh the file
77          * @param {Roo.bootstrap.DocumentManager} this
78          */
79         "refresh" : true,
80         /**
81          * @event click
82          * Fire after click the image
83          * @param {Roo.bootstrap.DocumentManager} this
84          * @param {Object} file
85          */
86         "click" : true,
87         /**
88          * @event edit
89          * Fire when upload a image and editable set to true
90          * @param {Roo.bootstrap.DocumentManager} this
91          * @param {Object} file
92          */
93         "edit" : true,
94         /**
95          * @event beforeselectfile
96          * Fire before select file
97          * @param {Roo.bootstrap.DocumentManager} this
98          */
99         "beforeselectfile" : true,
100         /**
101          * @event process
102          * Fire before process file
103          * @param {Roo.bootstrap.DocumentManager} this
104          * @param {Object} file
105          */
106         "process" : true
107         
108     });
109 };
110
111 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
112     
113     boxes : 0,
114     inputName : '',
115     thumbSize : 300,
116     multiple : true,
117     files : false,
118     method : 'POST',
119     url : '',
120     paramName : 'imageUpload',
121     fieldLabel : '',
122     labelWidth : 4,
123     labelAlign : 'left',
124     editable : true,
125     delegates : false,
126     
127     
128     xhr : false, 
129     
130     getAutoCreate : function()
131     {   
132         var managerWidget = {
133             tag : 'div',
134             cls : 'roo-document-manager',
135             cn : [
136                 {
137                     tag : 'input',
138                     cls : 'roo-document-manager-selector',
139                     type : 'file'
140                 },
141                 {
142                     tag : 'div',
143                     cls : 'roo-document-manager-uploader',
144                     cn : [
145                         {
146                             tag : 'div',
147                             cls : 'roo-document-manager-upload-btn',
148                             html : '<i class="fa fa-plus"></i>'
149                         }
150                     ]
151                     
152                 }
153             ]
154         };
155         
156         var content = [
157             {
158                 tag : 'div',
159                 cls : 'column col-md-12',
160                 cn : managerWidget
161             }
162         ];
163         
164         if(this.fieldLabel.length){
165             
166             content = [
167                 {
168                     tag : 'div',
169                     cls : 'column col-md-12',
170                     html : this.fieldLabel
171                 },
172                 {
173                     tag : 'div',
174                     cls : 'column col-md-12',
175                     cn : managerWidget
176                 }
177             ];
178
179             if(this.labelAlign == 'left'){
180                 content = [
181                     {
182                         tag : 'div',
183                         cls : 'column col-md-' + this.labelWidth,
184                         html : this.fieldLabel
185                     },
186                     {
187                         tag : 'div',
188                         cls : 'column col-md-' + (12 - this.labelWidth),
189                         cn : managerWidget
190                     }
191                 ];
192                 
193             }
194         }
195         
196         var cfg = {
197             tag : 'div',
198             cls : 'row clearfix',
199             cn : content
200         };
201         
202         return cfg;
203         
204     },
205     
206     initEvents : function()
207     {
208         this.managerEl = this.el.select('.roo-document-manager', true).first();
209         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
210         
211         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
212         this.selectorEl.hide();
213         
214         if(this.multiple){
215             this.selectorEl.attr('multiple', 'multiple');
216         }
217         
218         this.selectorEl.on('change', this.onFileSelected, this);
219         
220         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
221         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
222         
223         this.uploader.on('click', this.onUploaderClick, this);
224         
225         this.renderProgressDialog();
226         
227         var _this = this;
228         
229         window.addEventListener("resize", function() { _this.refresh(); } );
230         
231         this.fireEvent('initial', this);
232     },
233     
234     renderProgressDialog : function()
235     {
236         var _this = this;
237         
238         this.progressDialog = new Roo.bootstrap.Modal({
239             cls : 'roo-document-manager-progress-dialog',
240             allow_close : false,
241             title : '',
242             buttons : [
243                 {
244                     name  :'cancel',
245                     weight : 'danger',
246                     html : 'Cancel'
247                 }
248             ], 
249             listeners : { 
250                 btnclick : function() {
251                     _this.uploadCancel();
252                     this.hide();
253                 }
254             }
255         });
256          
257         this.progressDialog.render(Roo.get(document.body));
258          
259         this.progress = new Roo.bootstrap.Progress({
260             cls : 'roo-document-manager-progress',
261             active : true,
262             striped : true
263         });
264         
265         this.progress.render(this.progressDialog.getChildContainer());
266         
267         this.progressBar = new Roo.bootstrap.ProgressBar({
268             cls : 'roo-document-manager-progress-bar',
269             aria_valuenow : 0,
270             aria_valuemin : 0,
271             aria_valuemax : 12,
272             panel : 'success'
273         });
274         
275         this.progressBar.render(this.progress.getChildContainer());
276     },
277     
278     onUploaderClick : function(e)
279     {
280         e.preventDefault();
281      
282         if(this.fireEvent('beforeselectfile', this) != false){
283             this.selectorEl.dom.click();
284         }
285         
286     },
287     
288     onFileSelected : function(e)
289     {
290         e.preventDefault();
291         
292         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
293             return;
294         }
295         
296         Roo.each(this.selectorEl.dom.files, function(file){
297             if(this.fireEvent('inspect', this, file) != false){
298                 this.files.push(file);
299             }
300         }, this);
301         
302         this.queue();
303         
304     },
305     
306     queue : function()
307     {
308         this.selectorEl.dom.value = '';
309         
310         if(!this.files.length){
311             return;
312         }
313         
314         if(this.boxes > 0 && this.files.length > this.boxes){
315             this.files = this.files.slice(0, this.boxes);
316         }
317         
318         this.uploader.show();
319         
320         if(this.boxes > 0 && this.files.length > this.boxes - 1){
321             this.uploader.hide();
322         }
323         
324         var _this = this;
325         
326         var files = [];
327         
328         var docs = [];
329         
330         Roo.each(this.files, function(file){
331             
332             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
333                 var f = this.renderPreview(file);
334                 files.push(f);
335                 return;
336             }
337             
338             if(file.type.indexOf('image') != -1){
339                 this.delegates.push(
340                     (function(){
341                         _this.process(file);
342                     }).createDelegate(this)
343                 );
344         
345                 return;
346             }
347             
348             docs.push(
349                 (function(){
350                     _this.process(file);
351                 }).createDelegate(this)
352             );
353             
354         }, this);
355         
356         this.files = files;
357         
358         this.delegates = this.delegates.concat(docs);
359         
360         if(!this.delegates.length){
361             this.refresh();
362             return;
363         }
364         
365         this.progressBar.aria_valuemax = this.delegates.length;
366         
367         this.arrange();
368         
369         return;
370     },
371     
372     arrange : function()
373     {
374         if(!this.delegates.length){
375             this.progressDialog.hide();
376             this.refresh();
377             return;
378         }
379         
380         var delegate = this.delegates.shift();
381         
382         this.progressDialog.show();
383         
384         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
385         
386         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
387         
388         delegate();
389     },
390     
391     refresh : function()
392     {
393         this.uploader.show();
394         
395         if(this.boxes > 0 && this.files.length > this.boxes - 1){
396             this.uploader.hide();
397         }
398         
399         Roo.isTouch ? this.closable(false) : this.closable(true);
400         
401         this.fireEvent('refresh', this);
402     },
403     
404     onRemove : function(e, el, o)
405     {
406         e.preventDefault();
407         
408         this.fireEvent('remove', this, o);
409         
410     },
411     
412     remove : function(o)
413     {
414         var files = [];
415         
416         Roo.each(this.files, function(file){
417             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
418                 files.push(file);
419                 return;
420             }
421
422             o.target.remove();
423
424         }, this);
425         
426         this.files = files;
427         
428         this.refresh();
429     },
430     
431     clear : function()
432     {
433         Roo.each(this.files, function(file){
434             if(!file.target){
435                 return;
436             }
437             
438             file.target.remove();
439
440         }, this);
441         
442         this.files = [];
443         
444         this.refresh();
445     },
446     
447     onClick : function(e, el, o)
448     {
449         e.preventDefault();
450         
451         this.fireEvent('click', this, o);
452         
453     },
454     
455     closable : function(closable)
456     {
457         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
458             
459             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
460             
461             if(closable){
462                 el.show();
463                 return;
464             }
465             
466             el.hide();
467             
468         }, this);
469     },
470     
471     xhrOnLoad : function(xhr)
472     {
473         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
474             el.remove();
475         }, this);
476         
477         if (xhr.readyState !== 4) {
478             this.arrange();
479             this.fireEvent('exception', this, xhr);
480             return;
481         }
482
483         var response = Roo.decode(xhr.responseText);
484         
485         if(!response.success){
486             this.arrange();
487             this.fireEvent('exception', this, xhr);
488             return;
489         }
490         
491         var file = this.renderPreview(response.data);
492         
493         this.files.push(file);
494         
495         this.arrange();
496         
497         this.fireEvent('afterupload', this, xhr);
498         
499     },
500     
501     xhrOnError : function(xhr)
502     {
503         Roo.log('xhr on error');
504         
505         var response = Roo.decode(xhr.responseText);
506           
507         Roo.log(response);
508         
509         this.arrange();
510     },
511     
512     process : function(file)
513     {
514         if(this.fireEvent('process', this, file) !== false){
515             if(this.editable && file.type.indexOf('image') != -1){
516                 this.fireEvent('edit', this, file);
517                 return;
518             }
519
520             this.uploadStart(file, false);
521
522             return;
523         }
524         
525     },
526     
527     uploadStart : function(file, crop)
528     {
529         this.xhr = new XMLHttpRequest();
530         
531         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
532             this.arrange();
533             return;
534         }
535         
536         file.xhr = this.xhr;
537             
538         this.managerEl.createChild({
539             tag : 'div',
540             cls : 'roo-document-manager-loading',
541             cn : [
542                 {
543                     tag : 'div',
544                     tooltip : file.name,
545                     cls : 'roo-document-manager-thumb',
546                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
547                 }
548             ]
549
550         });
551
552         this.xhr.open(this.method, this.url, true);
553         
554         var headers = {
555             "Accept": "application/json",
556             "Cache-Control": "no-cache",
557             "X-Requested-With": "XMLHttpRequest"
558         };
559         
560         for (var headerName in headers) {
561             var headerValue = headers[headerName];
562             if (headerValue) {
563                 this.xhr.setRequestHeader(headerName, headerValue);
564             }
565         }
566         
567         var _this = this;
568         
569         this.xhr.onload = function()
570         {
571             _this.xhrOnLoad(_this.xhr);
572         }
573         
574         this.xhr.onerror = function()
575         {
576             _this.xhrOnError(_this.xhr);
577         }
578         
579         var formData = new FormData();
580
581         formData.append('returnHTML', 'NO');
582         
583         if(crop){
584             formData.append('crop', crop);
585         }
586         
587         formData.append(this.paramName, file, file.name);
588         
589         if(this.fireEvent('prepare', this, formData, file) != false){
590             this.xhr.send(formData);
591             return
592         };
593         
594         this.uploadCancel();
595     },
596     
597     uploadCancel : function()
598     {
599         if (this.xhr) {
600             this.xhr.abort();
601         }
602         
603         this.delegates = [];
604         
605         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
606             el.remove();
607         }, this);
608         
609         this.arrange();
610     },
611     
612     renderPreview : function(file)
613     {
614         if(typeof(file.target) != 'undefined' && file.target){
615             return file;
616         }
617         
618         var previewEl = this.managerEl.createChild({
619             tag : 'div',
620             cls : 'roo-document-manager-preview',
621             cn : [
622                 {
623                     tag : 'div',
624                     tooltip : file.filename,
625                     cls : 'roo-document-manager-thumb',
626                     html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
627                 },
628                 {
629                     tag : 'button',
630                     cls : 'close',
631                     html : '<i class="fa fa-times-circle"></i>'
632                 }
633             ]
634         });
635
636         var close = previewEl.select('button.close', true).first();
637
638         close.on('click', this.onRemove, this, file);
639
640         file.target = previewEl;
641
642         var image = previewEl.select('img', true).first();
643         
644         var _this = this;
645         
646         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
647         
648         image.on('click', this.onClick, this, file);
649         
650         return file;
651         
652     },
653     
654     onPreviewLoad : function(file, image)
655     {
656         if(typeof(file.target) == 'undefined' || !file.target){
657             return;
658         }
659         
660         var width = image.dom.naturalWidth || image.dom.width;
661         var height = image.dom.naturalHeight || image.dom.height;
662         
663         if(width > height){
664             file.target.addClass('wide');
665             return;
666         }
667         
668         file.target.addClass('tall');
669         return;
670         
671     },
672     
673     uploadFromSource : function(file, crop)
674     {
675         this.xhr = new XMLHttpRequest();
676         
677         this.managerEl.createChild({
678             tag : 'div',
679             cls : 'roo-document-manager-loading',
680             cn : [
681                 {
682                     tag : 'div',
683                     tooltip : file.name,
684                     cls : 'roo-document-manager-thumb',
685                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
686                 }
687             ]
688
689         });
690
691         this.xhr.open(this.method, this.url, true);
692         
693         var headers = {
694             "Accept": "application/json",
695             "Cache-Control": "no-cache",
696             "X-Requested-With": "XMLHttpRequest"
697         };
698         
699         for (var headerName in headers) {
700             var headerValue = headers[headerName];
701             if (headerValue) {
702                 this.xhr.setRequestHeader(headerName, headerValue);
703             }
704         }
705         
706         var _this = this;
707         
708         this.xhr.onload = function()
709         {
710             _this.xhrOnLoad(_this.xhr);
711         }
712         
713         this.xhr.onerror = function()
714         {
715             _this.xhrOnError(_this.xhr);
716         }
717         
718         var formData = new FormData();
719
720         formData.append('returnHTML', 'NO');
721         
722         formData.append('crop', crop);
723         
724         if(typeof(file.filename) != 'undefined'){
725             formData.append('filename', file.filename);
726         }
727         
728         if(typeof(file.mimetype) != 'undefined'){
729             formData.append('mimetype', file.mimetype);
730         }
731         
732         if(this.fireEvent('prepare', this, formData) != false){
733             this.xhr.send(formData);
734         };
735     }
736 });