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