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     });
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('beforeprocess', this, file) !== false){
494             
495             if(this.editable && file.type.indexOf('image') != -1){
496                 this.fireEvent('edit', this, file);
497                 return;
498             }
499
500             this.uploadStart(file, false);
501
502             return;
503         }
504         
505     },
506     
507     uploadStart : function(file, crop)
508     {
509         this.xhr = new XMLHttpRequest();
510         
511         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
512             this.arrange();
513             return;
514         }
515         
516         file.xhr = this.xhr;
517             
518         this.managerEl.createChild({
519             tag : 'div',
520             cls : 'roo-document-manager-loading',
521             cn : [
522                 {
523                     tag : 'div',
524                     tooltip : file.name,
525                     cls : 'roo-document-manager-thumb',
526                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
527                 }
528             ]
529
530         });
531
532         this.xhr.open(this.method, this.url, true);
533         
534         var headers = {
535             "Accept": "application/json",
536             "Cache-Control": "no-cache",
537             "X-Requested-With": "XMLHttpRequest"
538         };
539         
540         for (var headerName in headers) {
541             var headerValue = headers[headerName];
542             if (headerValue) {
543                 this.xhr.setRequestHeader(headerName, headerValue);
544             }
545         }
546         
547         var _this = this;
548         
549         this.xhr.onload = function()
550         {
551             _this.xhrOnLoad(_this.xhr);
552         }
553         
554         this.xhr.onerror = function()
555         {
556             _this.xhrOnError(_this.xhr);
557         }
558         
559         var formData = new FormData();
560
561         formData.append('returnHTML', 'NO');
562         
563         if(crop){
564             formData.append('crop', crop);
565         }
566         
567         formData.append(this.paramName, file, file.name);
568         
569         if(this.fireEvent('prepare', this, formData) != false){
570             this.xhr.send(formData);
571         };
572     },
573     
574     uploadCancel : function()
575     {
576         this.xhr.abort();
577         
578         this.delegates = [];
579         
580         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
581             el.remove();
582         }, this);
583         
584         this.arrange();
585     },
586     
587     renderPreview : function(file)
588     {
589         if(typeof(file.target) != 'undefined' && file.target){
590             return file;
591         }
592         
593         var previewEl = this.managerEl.createChild({
594             tag : 'div',
595             cls : 'roo-document-manager-preview',
596             cn : [
597                 {
598                     tag : 'div',
599                     tooltip : file.filename,
600                     cls : 'roo-document-manager-thumb',
601                     html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
602                 },
603                 {
604                     tag : 'button',
605                     cls : 'close',
606                     html : '<i class="fa fa-times-circle"></i>'
607                 }
608             ]
609         });
610
611         var close = previewEl.select('button.close', true).first();
612
613         close.on('click', this.onRemove, this, file);
614
615         file.target = previewEl;
616
617         var image = previewEl.select('img', true).first();
618         
619         var _this = this;
620         
621         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
622         
623         image.on('click', this.onClick, this, file);
624         
625         return file;
626         
627     },
628     
629     onPreviewLoad : function(file, image)
630     {
631         if(typeof(file.target) == 'undefined' || !file.target){
632             return;
633         }
634         
635         var width = image.dom.naturalWidth || image.dom.width;
636         var height = image.dom.naturalHeight || image.dom.height;
637         
638         if(width > height){
639             file.target.addClass('wide');
640             return;
641         }
642         
643         file.target.addClass('tall');
644         return;
645         
646     },
647     
648     uploadFromSource : function(file, crop)
649     {
650         this.xhr = new XMLHttpRequest();
651         
652         this.managerEl.createChild({
653             tag : 'div',
654             cls : 'roo-document-manager-loading',
655             cn : [
656                 {
657                     tag : 'div',
658                     tooltip : file.name,
659                     cls : 'roo-document-manager-thumb',
660                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
661                 }
662             ]
663
664         });
665
666         this.xhr.open(this.method, this.url, true);
667         
668         var headers = {
669             "Accept": "application/json",
670             "Cache-Control": "no-cache",
671             "X-Requested-With": "XMLHttpRequest"
672         };
673         
674         for (var headerName in headers) {
675             var headerValue = headers[headerName];
676             if (headerValue) {
677                 this.xhr.setRequestHeader(headerName, headerValue);
678             }
679         }
680         
681         var _this = this;
682         
683         this.xhr.onload = function()
684         {
685             _this.xhrOnLoad(_this.xhr);
686         }
687         
688         this.xhr.onerror = function()
689         {
690             _this.xhrOnError(_this.xhr);
691         }
692         
693         var formData = new FormData();
694
695         formData.append('returnHTML', 'NO');
696         
697         formData.append('crop', crop);
698         
699         if(typeof(file.filename) != 'undefined'){
700             formData.append('filename', file.filename);
701         }
702         
703         if(typeof(file.mimetype) != 'undefined'){
704             formData.append('mimetype', file.mimetype);
705         }
706         
707         if(this.fireEvent('prepare', this, formData) != false){
708             this.xhr.send(formData);
709         };
710     }
711 });