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