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