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