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