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