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