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