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             title : '',
289             buttons : [
290                 {
291                     name  :'cancel',
292                     weight : 'danger',
293                     html : 'Cancel'
294                 }
295             ], 
296             listeners : { 
297                 btnclick : function() {
298                     _this.uploadCancel();
299                     this.hide();
300                 }
301             }
302         });
303          
304         this.progressDialog.render(Roo.get(document.body));
305          
306         this.progress = new Roo.bootstrap.Progress({
307             cls : 'roo-document-manager-progress',
308             active : true,
309             striped : true
310         });
311         
312         this.progress.render(this.progressDialog.getChildContainer());
313         
314         this.progressBar = new Roo.bootstrap.ProgressBar({
315             cls : 'roo-document-manager-progress-bar',
316             aria_valuenow : 0,
317             aria_valuemin : 0,
318             aria_valuemax : 12,
319             panel : 'success'
320         });
321         
322         this.progressBar.render(this.progress.getChildContainer());
323     },
324     
325     onUploaderClick : function(e)
326     {
327         e.preventDefault();
328      
329         if(this.fireEvent('beforeselectfile', this) != false){
330             this.selectorEl.dom.click();
331         }
332         
333     },
334     
335     onFileSelected : function(e)
336     {
337         e.preventDefault();
338         
339         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
340             return;
341         }
342         
343         Roo.each(this.selectorEl.dom.files, function(file){
344             if(this.fireEvent('inspect', this, file) != false){
345                 this.files.push(file);
346             }
347         }, this);
348         
349         this.queue();
350         
351     },
352     
353     queue : function()
354     {
355         this.selectorEl.dom.value = '';
356         
357         if(!this.files || !this.files.length){
358             return;
359         }
360         
361         if(this.boxes > 0 && this.files.length > this.boxes){
362             this.files = this.files.slice(0, this.boxes);
363         }
364         
365         this.uploader.show();
366         
367         if(this.boxes > 0 && this.files.length > this.boxes - 1){
368             this.uploader.hide();
369         }
370         
371         var _this = this;
372         
373         var files = [];
374         
375         var docs = [];
376         
377         Roo.each(this.files, function(file){
378             
379             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
380                 var f = this.renderPreview(file);
381                 files.push(f);
382                 return;
383             }
384             
385             if(file.type.indexOf('image') != -1){
386                 this.delegates.push(
387                     (function(){
388                         _this.process(file);
389                     }).createDelegate(this)
390                 );
391         
392                 return;
393             }
394             
395             docs.push(
396                 (function(){
397                     _this.process(file);
398                 }).createDelegate(this)
399             );
400             
401         }, this);
402         
403         this.files = files;
404         
405         this.delegates = this.delegates.concat(docs);
406         
407         if(!this.delegates.length){
408             this.refresh();
409             return;
410         }
411         
412         this.progressBar.aria_valuemax = this.delegates.length;
413         
414         this.arrange();
415         
416         return;
417     },
418     
419     arrange : function()
420     {
421         if(!this.delegates.length){
422             this.progressDialog.hide();
423             this.refresh();
424             return;
425         }
426         
427         var delegate = this.delegates.shift();
428         
429         this.progressDialog.show();
430         
431         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
432         
433         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
434         
435         delegate();
436     },
437     
438     refresh : function()
439     {
440         this.uploader.show();
441         
442         if(this.boxes > 0 && this.files.length > this.boxes - 1){
443             this.uploader.hide();
444         }
445         
446         Roo.isTouch ? this.closable(false) : this.closable(true);
447         
448         this.fireEvent('refresh', this);
449     },
450     
451     onRemove : function(e, el, o)
452     {
453         e.preventDefault();
454         
455         this.fireEvent('remove', this, o);
456         
457     },
458     
459     remove : function(o)
460     {
461         var files = [];
462         
463         Roo.each(this.files, function(file){
464             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
465                 files.push(file);
466                 return;
467             }
468
469             o.target.remove();
470
471         }, this);
472         
473         this.files = files;
474         
475         this.refresh();
476     },
477     
478     clear : function()
479     {
480         Roo.each(this.files, function(file){
481             if(!file.target){
482                 return;
483             }
484             
485             file.target.remove();
486
487         }, this);
488         
489         this.files = [];
490         
491         this.refresh();
492     },
493     
494     onClick : function(e, el, o)
495     {
496         e.preventDefault();
497         
498         this.fireEvent('click', this, o);
499         
500     },
501     
502     closable : function(closable)
503     {
504         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
505             
506             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
507             
508             if(closable){
509                 el.show();
510                 return;
511             }
512             
513             el.hide();
514             
515         }, this);
516     },
517     
518     xhrOnLoad : function(xhr)
519     {
520         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
521             el.remove();
522         }, this);
523         
524         if (xhr.readyState !== 4) {
525             this.arrange();
526             this.fireEvent('exception', this, xhr);
527             return;
528         }
529
530         var response = Roo.decode(xhr.responseText);
531         
532         if(!response.success){
533             this.arrange();
534             this.fireEvent('exception', this, xhr);
535             return;
536         }
537         
538         var file = this.renderPreview(response.data);
539         
540         this.files.push(file);
541         
542         this.arrange();
543         
544         this.fireEvent('afterupload', this, xhr);
545         
546     },
547     
548     xhrOnError : function(xhr)
549     {
550         Roo.log('xhr on error');
551         
552         var response = Roo.decode(xhr.responseText);
553           
554         Roo.log(response);
555         
556         this.arrange();
557     },
558     
559     process : function(file)
560     {
561         if(this.fireEvent('process', this, file) !== false){
562             if(this.editable && file.type.indexOf('image') != -1){
563                 this.fireEvent('edit', this, file);
564                 return;
565             }
566
567             this.uploadStart(file, false);
568
569             return;
570         }
571         
572     },
573     
574     uploadStart : function(file, crop)
575     {
576         this.xhr = new XMLHttpRequest();
577         
578         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
579             this.arrange();
580             return;
581         }
582         
583         file.xhr = this.xhr;
584             
585         this.managerEl.createChild({
586             tag : 'div',
587             cls : 'roo-document-manager-loading',
588             cn : [
589                 {
590                     tag : 'div',
591                     tooltip : file.name,
592                     cls : 'roo-document-manager-thumb',
593                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
594                 }
595             ]
596
597         });
598
599         this.xhr.open(this.method, this.url, true);
600         
601         var headers = {
602             "Accept": "application/json",
603             "Cache-Control": "no-cache",
604             "X-Requested-With": "XMLHttpRequest"
605         };
606         
607         for (var headerName in headers) {
608             var headerValue = headers[headerName];
609             if (headerValue) {
610                 this.xhr.setRequestHeader(headerName, headerValue);
611             }
612         }
613         
614         var _this = this;
615         
616         this.xhr.onload = function()
617         {
618             _this.xhrOnLoad(_this.xhr);
619         }
620         
621         this.xhr.onerror = function()
622         {
623             _this.xhrOnError(_this.xhr);
624         }
625         
626         var formData = new FormData();
627
628         formData.append('returnHTML', 'NO');
629         
630         if(crop){
631             formData.append('crop', crop);
632         }
633         
634         formData.append(this.paramName, file, file.name);
635         
636         var options = {
637             file : file, 
638             manually : false
639         };
640         
641         if(this.fireEvent('prepare', this, formData, options) != false){
642             
643             if(options.manually){
644                 return;
645             }
646             
647             this.xhr.send(formData);
648             return;
649         };
650         
651         this.uploadCancel();
652     },
653     
654     uploadCancel : function()
655     {
656         if (this.xhr) {
657             this.xhr.abort();
658         }
659         
660         this.delegates = [];
661         
662         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
663             el.remove();
664         }, this);
665         
666         this.arrange();
667     },
668     
669     renderPreview : function(file)
670     {
671         if(typeof(file.target) != 'undefined' && file.target){
672             return file;
673         }
674         
675         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
676         
677         var previewEl = this.managerEl.createChild({
678             tag : 'div',
679             cls : 'roo-document-manager-preview',
680             cn : [
681                 {
682                     tag : 'div',
683                     tooltip : file[this.toolTipName],
684                     cls : 'roo-document-manager-thumb',
685                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
686                 },
687                 {
688                     tag : 'button',
689                     cls : 'close',
690                     html : '<i class="fa fa-times-circle"></i>'
691                 }
692             ]
693         });
694
695         var close = previewEl.select('button.close', true).first();
696
697         close.on('click', this.onRemove, this, file);
698
699         file.target = previewEl;
700
701         var image = previewEl.select('img', true).first();
702         
703         var _this = this;
704         
705         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
706         
707         image.on('click', this.onClick, this, file);
708         
709         this.fireEvent('previewrendered', this, file);
710         
711         return file;
712         
713     },
714     
715     onPreviewLoad : function(file, image)
716     {
717         if(typeof(file.target) == 'undefined' || !file.target){
718             return;
719         }
720         
721         var width = image.dom.naturalWidth || image.dom.width;
722         var height = image.dom.naturalHeight || image.dom.height;
723         
724         if(!this.previewResize) {
725             return;
726         }
727         
728         if(width > height){
729             file.target.addClass('wide');
730             return;
731         }
732         
733         file.target.addClass('tall');
734         return;
735         
736     },
737     
738     uploadFromSource : function(file, crop)
739     {
740         this.xhr = new XMLHttpRequest();
741         
742         this.managerEl.createChild({
743             tag : 'div',
744             cls : 'roo-document-manager-loading',
745             cn : [
746                 {
747                     tag : 'div',
748                     tooltip : file.name,
749                     cls : 'roo-document-manager-thumb',
750                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
751                 }
752             ]
753
754         });
755
756         this.xhr.open(this.method, this.url, true);
757         
758         var headers = {
759             "Accept": "application/json",
760             "Cache-Control": "no-cache",
761             "X-Requested-With": "XMLHttpRequest"
762         };
763         
764         for (var headerName in headers) {
765             var headerValue = headers[headerName];
766             if (headerValue) {
767                 this.xhr.setRequestHeader(headerName, headerValue);
768             }
769         }
770         
771         var _this = this;
772         
773         this.xhr.onload = function()
774         {
775             _this.xhrOnLoad(_this.xhr);
776         }
777         
778         this.xhr.onerror = function()
779         {
780             _this.xhrOnError(_this.xhr);
781         }
782         
783         var formData = new FormData();
784
785         formData.append('returnHTML', 'NO');
786         
787         formData.append('crop', crop);
788         
789         if(typeof(file.filename) != 'undefined'){
790             formData.append('filename', file.filename);
791         }
792         
793         if(typeof(file.mimetype) != 'undefined'){
794             formData.append('mimetype', file.mimetype);
795         }
796         
797         Roo.log(formData);
798         
799         if(this.fireEvent('prepare', this, formData) != false){
800             this.xhr.send(formData);
801         };
802     }
803 });