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