56e2b97913fbb17639a6ac5ba36307f6f6b5c8e2
[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         var docs = [];
310         
311         Roo.each(this.files, function(file){
312             
313             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
314                 var f = this.renderPreview(file);
315                 files.push(f);
316                 return;
317             }
318             
319             if(file.type.indexOf('image') != -1){
320                 this.delegates.push(
321                     (function(){
322                         _this.process(file);
323                     }).createDelegate(this)
324                 );
325         
326                 return;
327             }
328             
329             docs.push(
330                 (function(){
331                     _this.process(file);
332                 }).createDelegate(this)
333             );
334             
335         }, this);
336         
337         this.files = files;
338         
339         this.delegates = this.delegates.concat(docs);
340         
341         if(!this.delegates.length){
342             this.refresh();
343             return;
344         }
345         
346         this.progressBar.aria_valuemax = this.delegates.length;
347         
348         this.arrange();
349         
350         return;
351     },
352     
353     arrange : function()
354     {
355         if(!this.delegates.length){
356             this.progressDialog.hide();
357             this.refresh();
358             return;
359         }
360         
361         var delegate = this.delegates.shift();
362         
363         this.progressDialog.show();
364         
365         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
366         
367         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
368         
369         delegate();
370     },
371     
372     refresh : function()
373     {
374         this.uploader.show();
375         
376         if(this.boxes > 0 && this.files.length > this.boxes - 1){
377             this.uploader.hide();
378         }
379         
380         Roo.isTouch ? this.closable(false) : this.closable(true);
381         
382         this.fireEvent('refresh', this);
383     },
384     
385     onRemove : function(e, el, o)
386     {
387         e.preventDefault();
388         
389         this.fireEvent('remove', this, o);
390         
391     },
392     
393     remove : function(o)
394     {
395         var files = [];
396         
397         Roo.each(this.files, function(file){
398             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
399                 files.push(file);
400                 return;
401             }
402
403             o.target.remove();
404
405         }, this);
406         
407         this.files = files;
408         
409         this.refresh();
410     },
411     
412     clear : function()
413     {
414         Roo.each(this.files, function(file){
415             if(!file.target){
416                 return;
417             }
418             
419             file.target.remove();
420
421         }, this);
422         
423         this.files = [];
424         
425         this.refresh();
426     },
427     
428     onClick : function(e, el, o)
429     {
430         e.preventDefault();
431         
432         this.fireEvent('click', this, o);
433         
434     },
435     
436     closable : function(closable)
437     {
438         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
439             
440             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
441             
442             if(closable){
443                 el.show();
444                 return;
445             }
446             
447             el.hide();
448             
449         }, this);
450     },
451     
452     xhrOnLoad : function(xhr)
453     {
454         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
455             el.remove();
456         }, this);
457         
458         if (xhr.readyState !== 4) {
459             this.arrange();
460             this.fireEvent('exception', this, xhr);
461             return;
462         }
463
464         var response = Roo.decode(xhr.responseText);
465         
466         if(!response.success){
467             this.arrange();
468             this.fireEvent('exception', this, xhr);
469             return;
470         }
471         
472         var file = this.renderPreview(response.data);
473         
474         this.files.push(file);
475         
476         this.arrange();
477         
478     },
479     
480     xhrOnError : function()
481     {
482         Roo.log('xhr on error');
483         
484         var response = Roo.decode(xhr.responseText);
485           
486         Roo.log(response);
487         
488         this.arrange();
489     },
490     
491     process : function(file)
492     {
493         if(this.fireEvent('process', this, file) !== false){
494             if(this.editable && file.type.indexOf('image') != -1){
495                 this.fireEvent('edit', this, file);
496                 return;
497             }
498
499             this.uploadStart(file, false);
500
501             return;
502         }
503         
504     },
505     
506     uploadStart : function(file, crop)
507     {
508         this.xhr = new XMLHttpRequest();
509         
510         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
511             this.arrange();
512             return;
513         }
514         
515         file.xhr = this.xhr;
516             
517         this.managerEl.createChild({
518             tag : 'div',
519             cls : 'roo-document-manager-loading',
520             cn : [
521                 {
522                     tag : 'div',
523                     tooltip : file.name,
524                     cls : 'roo-document-manager-thumb',
525                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
526                 }
527             ]
528
529         });
530
531         this.xhr.open(this.method, this.url, true);
532         
533         var headers = {
534             "Accept": "application/json",
535             "Cache-Control": "no-cache",
536             "X-Requested-With": "XMLHttpRequest"
537         };
538         
539         for (var headerName in headers) {
540             var headerValue = headers[headerName];
541             if (headerValue) {
542                 this.xhr.setRequestHeader(headerName, headerValue);
543             }
544         }
545         
546         var _this = this;
547         
548         this.xhr.onload = function()
549         {
550             _this.xhrOnLoad(_this.xhr);
551         }
552         
553         this.xhr.onerror = function()
554         {
555             _this.xhrOnError(_this.xhr);
556         }
557         
558         var formData = new FormData();
559
560         formData.append('returnHTML', 'NO');
561         
562         if(crop){
563             formData.append('crop', crop);
564         }
565         
566         formData.append(this.paramName, file, file.name);
567         
568         if(this.fireEvent('prepare', this, formData) != false){
569             this.xhr.send(formData);
570         };
571     },
572     
573     uploadCancel : function()
574     {
575         this.xhr.abort();
576         
577         this.delegates = [];
578         
579         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
580             el.remove();
581         }, this);
582         
583         this.arrange();
584     },
585     
586     renderPreview : function(file)
587     {
588         if(typeof(file.target) != 'undefined' && file.target){
589             return file;
590         }
591         
592         var previewEl = this.managerEl.createChild({
593             tag : 'div',
594             cls : 'roo-document-manager-preview',
595             cn : [
596                 {
597                     tag : 'div',
598                     tooltip : file.filename,
599                     cls : 'roo-document-manager-thumb',
600                     html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
601                 },
602                 {
603                     tag : 'button',
604                     cls : 'close',
605                     html : '<i class="fa fa-times-circle"></i>'
606                 }
607             ]
608         });
609
610         var close = previewEl.select('button.close', true).first();
611
612         close.on('click', this.onRemove, this, file);
613
614         file.target = previewEl;
615
616         var image = previewEl.select('img', true).first();
617         
618         var _this = this;
619         
620         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
621         
622         image.on('click', this.onClick, this, file);
623         
624         return file;
625         
626     },
627     
628     onPreviewLoad : function(file, image)
629     {
630         if(typeof(file.target) == 'undefined' || !file.target){
631             return;
632         }
633         
634         var width = image.dom.naturalWidth || image.dom.width;
635         var height = image.dom.naturalHeight || image.dom.height;
636         
637         if(width > height){
638             file.target.addClass('wide');
639             return;
640         }
641         
642         file.target.addClass('tall');
643         return;
644         
645     },
646     
647     uploadFromSource : function(file, crop)
648     {
649         this.xhr = new XMLHttpRequest();
650         
651         this.managerEl.createChild({
652             tag : 'div',
653             cls : 'roo-document-manager-loading',
654             cn : [
655                 {
656                     tag : 'div',
657                     tooltip : file.name,
658                     cls : 'roo-document-manager-thumb',
659                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
660                 }
661             ]
662
663         });
664
665         this.xhr.open(this.method, this.url, true);
666         
667         var headers = {
668             "Accept": "application/json",
669             "Cache-Control": "no-cache",
670             "X-Requested-With": "XMLHttpRequest"
671         };
672         
673         for (var headerName in headers) {
674             var headerValue = headers[headerName];
675             if (headerValue) {
676                 this.xhr.setRequestHeader(headerName, headerValue);
677             }
678         }
679         
680         var _this = this;
681         
682         this.xhr.onload = function()
683         {
684             _this.xhrOnLoad(_this.xhr);
685         }
686         
687         this.xhr.onerror = function()
688         {
689             _this.xhrOnError(_this.xhr);
690         }
691         
692         var formData = new FormData();
693
694         formData.append('returnHTML', 'NO');
695         
696         formData.append('crop', crop);
697         
698         if(typeof(file.filename) != 'undefined'){
699             formData.append('filename', file.filename);
700         }
701         
702         if(typeof(file.mimetype) != 'undefined'){
703             formData.append('mimetype', file.mimetype);
704         }
705         
706         if(this.fireEvent('prepare', this, formData) != false){
707             this.xhr.send(formData);
708         };
709     }
710 });