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         this.selectorEl.dom.click();
261     },
262     
263     onFileSelected : function(e)
264     {
265         e.preventDefault();
266         
267         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
268             return;
269         }
270         
271         Roo.each(this.selectorEl.dom.files, function(file){
272             if(this.fireEvent('inspect', this, file) != false){
273                 this.files.push(file);
274             }
275         }, this);
276         
277         this.queue();
278         
279     },
280     
281     queue : function()
282     {
283         this.selectorEl.dom.value = '';
284         
285         if(!this.files.length){
286             return;
287         }
288         
289         if(this.files.length > this.boxes){
290             this.files = this.files.slice(0, this.boxes);
291         }
292         
293         this.uploader.show();
294         
295         if(this.files.length > this.boxes - 1){
296             this.uploader.hide();
297         }
298         
299         var _this = this;
300         
301         var files = [];
302         
303         Roo.each(this.files, function(file){
304             
305             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
306                 var f = this.renderPreview(file);
307                 Roo.log('render preive???');
308                 Roo.log(f);
309                 files.push(f);
310                 return;
311             }
312             
313             this.delegates.push(
314                 (function(){
315                     _this.process(file);
316                 }).createDelegate(this)
317             );
318             
319         }, this);
320         
321         this.files = files;
322         
323         if(!this.delegates.length){
324             this.refresh();
325             return;
326         }
327         
328         this.progressBar.aria_valuemax = this.delegates.length;
329         
330         this.arrange();
331         
332         return;
333     },
334     
335     arrange : function()
336     {
337         if(!this.delegates.length){
338             this.progressDialog.hide();
339             this.refresh();
340             return;
341         }
342         
343         var delegate = this.delegates.shift();
344         
345         this.progressDialog.show();
346         
347         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
348         
349         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
350         
351         delegate();
352     },
353     
354     refresh : function()
355     {
356         this.uploader.show();
357         
358         if(this.files.length > this.boxes - 1){
359             this.uploader.hide();
360         }
361         
362         Roo.isTouch ? this.closable(false) : this.closable(true);
363         
364         this.fireEvent('refresh', this);
365     },
366     
367     onRemove : function(e, el, o)
368     {
369         e.preventDefault();
370         
371         this.fireEvent('remove', this, o);
372         
373     },
374     
375     remove : function(o)
376     {
377         var files = [];
378         
379         Roo.each(this.files, function(file){
380             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
381                 files.push(file);
382                 return;
383             }
384
385             o.target.remove();
386
387         }, this);
388         
389         this.files = files;
390         
391         this.refresh();
392     },
393     
394     onClick : function(e, el, o)
395     {
396         e.preventDefault();
397         
398         this.fireEvent('click', this, o);
399         
400     },
401     
402     closable : function(closable)
403     {
404         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
405             
406             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
407             
408             if(closable){
409                 el.show();
410                 return;
411             }
412             
413             el.hide();
414             
415         }, this);
416     },
417     
418     xhrOnLoad : function(xhr)
419     {
420         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
421             el.remove();
422         }, this);
423         
424         if (xhr.readyState !== 4) {
425             this.arrange();
426             this.fireEvent('exception', this, xhr);
427             return;
428         }
429
430         var response = Roo.decode(xhr.responseText);
431         
432         if(!response.success){
433             this.arrange();
434             this.fireEvent('exception', this, xhr);
435             return;
436         }
437         
438         var file = this.renderPreview(response.data);
439         
440         this.files.push(file);
441         
442         this.arrange();
443         
444     },
445     
446     xhrOnError : function()
447     {
448         Roo.log('xhr on error');
449         
450         var response = Roo.decode(xhr.responseText);
451           
452         Roo.log(response);
453         
454         this.arrange();
455     },
456     
457     process : function(file)
458     {
459         if(this.editable && file.type.indexOf('image') != -1){
460             this.fireEvent('edit', this, file);
461             return;
462         }
463         
464         this.uploadStart(file, false);
465         
466         return;
467     },
468     
469     uploadStart : function(file, crop)
470     {
471         this.xhr = new XMLHttpRequest();
472         
473         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
474             this.arrange();
475             return;
476         }
477         
478         file.xhr = this.xhr;
479             
480         this.managerEl.createChild({
481             tag : 'div',
482             cls : 'roo-document-manager-loading',
483             cn : [
484                 {
485                     tag : 'div',
486                     tooltip : file.name,
487                     cls : 'roo-document-manager-thumb',
488                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
489                 }
490             ]
491
492         });
493
494         this.xhr.open(this.method, this.url, true);
495         
496         var headers = {
497             "Accept": "application/json",
498             "Cache-Control": "no-cache",
499             "X-Requested-With": "XMLHttpRequest"
500         };
501         
502         for (var headerName in headers) {
503             var headerValue = headers[headerName];
504             if (headerValue) {
505                 this.xhr.setRequestHeader(headerName, headerValue);
506             }
507         }
508         
509         var _this = this;
510         
511         this.xhr.onload = function()
512         {
513             _this.xhrOnLoad(_this.xhr);
514         }
515         
516         this.xhr.onerror = function()
517         {
518             _this.xhrOnError(_this.xhr);
519         }
520         
521         var formData = new FormData();
522
523         formData.append('returnHTML', 'NO');
524         
525         if(crop){
526             formData.append('crop', crop);
527         }
528         
529         formData.append(this.paramName, file, file.name);
530         
531         if(this.fireEvent('prepare', this, formData) != false){
532             this.xhr.send(formData);
533         };
534     },
535     
536     uploadCancel : function()
537     {
538         this.xhr.abort();
539         
540         this.delegates = [];
541         
542         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
543             el.remove();
544         }, this);
545         
546         this.arrange();
547     },
548     
549     renderPreview : function(file)
550     {
551         var _this = this;
552         
553         var imageEl = document.createElement('img');
554             
555         var _this = this;
556
557         imageEl.addEventListener("load", function(){ return _this.drawPreview(file, imageEl); });
558
559         imageEl.src = baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename;
560         
561     },
562     
563     drawPreview : function(file, imageEl)
564     {
565         var width = imageEl.naturalWidth || imageEl.width;
566         var height = imageEl.naturalHeight || imageEl.height;
567         
568         var preview = {
569             tag : 'div',
570             cls : 'roo-document-manager-preview tall',
571             cn : [
572                 {
573                     tag : 'div',
574                     tooltip : file.filename,
575                     cls : 'roo-document-manager-thumb',
576                     html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
577                 },
578                 {
579                     tag : 'button',
580                     cls : 'close',
581                     html : 'x'
582                 }
583             ]
584         }
585         
586         if(width > height){
587             preview = {
588                 tag : 'div',
589                 cls : 'roo-document-manager-preview wide',
590                 cn : [
591                     {
592                         tag : 'div',
593                         tooltip : file.filename,
594                         cls : 'roo-document-manager-thumb',
595                         html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
596                     },
597                     {
598                         tag : 'button',
599                         cls : 'close',
600                         html : 'x'
601                     }
602                 ]
603             }
604         }
605         
606         var previewEl = this.managerEl.createChild(preview);
607
608         var close = previewEl.select('button.close', true).first();
609
610         close.on('click', this.onRemove, this, file);
611
612         file.target = previewEl;
613
614         var image = previewEl.select('img', true).first();
615         
616         image.on('click', this.onClick, this, file);
617         
618         return file;
619         
620     }
621 });