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