Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / ux / statusbar / ValidationStatus.js
1 /**
2  * @class Ext.ux.statusbar.ValidationStatus
3  * A {@link Ext.StatusBar} plugin that provides automatic error notification when the
4  * associated form contains validation errors.
5  * @extends Ext.Component
6  * @constructor
7  * Creates a new ValiationStatus plugin
8  * @param {Object} config A config object
9  */
10 Ext.define('Ext.ux.statusbar.ValidationStatus', {
11     extend: 'Ext.Component', 
12     requires: ['Ext.util.MixedCollection'],
13     /**
14      * @cfg {String} errorIconCls
15      * The {@link #iconCls} value to be applied to the status message when there is a
16      * validation error. Defaults to <tt>'x-status-error'</tt>.
17      */
18     errorIconCls : 'x-status-error',
19     /**
20      * @cfg {String} errorListCls
21      * The css class to be used for the error list when there are validation errors.
22      * Defaults to <tt>'x-status-error-list'</tt>.
23      */
24     errorListCls : 'x-status-error-list',
25     /**
26      * @cfg {String} validIconCls
27      * The {@link #iconCls} value to be applied to the status message when the form
28      * validates. Defaults to <tt>'x-status-valid'</tt>.
29      */
30     validIconCls : 'x-status-valid',
31     
32     /**
33      * @cfg {String} showText
34      * The {@link #text} value to be applied when there is a form validation error.
35      * Defaults to <tt>'The form has errors (click for details...)'</tt>.
36      */
37     showText : 'The form has errors (click for details...)',
38     /**
39      * @cfg {String} showText
40      * The {@link #text} value to display when the error list is displayed.
41      * Defaults to <tt>'Click again to hide the error list'</tt>.
42      */
43     hideText : 'Click again to hide the error list',
44     /**
45      * @cfg {String} submitText
46      * The {@link #text} value to be applied when the form is being submitted.
47      * Defaults to <tt>'Saving...'</tt>.
48      */
49     submitText : 'Saving...',
50     
51     // private
52     init : function(sb){
53         sb.on('render', function(){
54             this.statusBar = sb;
55             this.monitor = true;
56             this.errors = Ext.create('Ext.util.MixedCollection');
57             this.listAlign = (sb.statusAlign === 'right' ? 'br-tr?' : 'bl-tl?');
58             
59             if (this.form) {
60                 this.formPanel = Ext.getCmp(this.form);
61                 this.basicForm = this.formPanel.getForm();
62                 this.startMonitoring();
63                 this.basicForm.on('beforeaction', function(f, action){
64                     if(action.type === 'submit'){
65                         // Ignore monitoring while submitting otherwise the field validation
66                         // events cause the status message to reset too early
67                         this.monitor = false;
68                     }
69                 }, this);
70                 var startMonitor = function(){
71                     this.monitor = true;
72                 };
73                 this.basicForm.on('actioncomplete', startMonitor, this);
74                 this.basicForm.on('actionfailed', startMonitor, this);
75             }
76         }, this, {single:true});
77         sb.on({
78             scope: this,
79             afterlayout:{
80                 single: true,
81                 fn: function(){
82                     // Grab the statusEl after the first layout.
83                     sb.statusEl.getEl().on('click', this.onStatusClick, this, {buffer:200});
84                 } 
85             }, 
86             beforedestroy:{
87                 single: true,
88                 fn: this.onDestroy
89             } 
90         });
91     },
92     
93     // private
94     startMonitoring : function() {
95         this.basicForm.getFields().each(function(f){
96             f.on('validitychange', this.onFieldValidation, this);
97         }, this);
98     },
99     
100     // private
101     stopMonitoring : function(){
102         this.basicForm.getFields().each(function(f){
103             f.un('validitychange', this.onFieldValidation, this);
104         }, this);
105     },
106     
107     // private
108     onDestroy : function(){
109         this.stopMonitoring();
110         this.statusBar.statusEl.un('click', this.onStatusClick, this);
111         this.callParent(arguments);
112     },
113     
114     // private
115     onFieldValidation : function(f, isValid){
116         if (!this.monitor) {
117             return false;
118         }
119         var msg = f.getErrors()[0];
120         if (msg) {
121             this.errors.add(f.id, {field:f, msg:msg});
122         } else {
123             this.errors.removeAtKey(f.id);
124         }
125         this.updateErrorList();
126         if(this.errors.getCount() > 0) {
127             if(this.statusBar.getText() !== this.showText){
128                 this.statusBar.setStatus({text:this.showText, iconCls:this.errorIconCls});
129             }
130         }else{
131             this.statusBar.clearStatus().setIcon(this.validIconCls);
132         }
133     },
134     
135     // private
136     updateErrorList : function(){
137         if(this.errors.getCount() > 0){
138          var msg = '<ul>';
139          this.errors.each(function(err){
140              msg += ('<li id="x-err-'+ err.field.id +'"><a href="#">' + err.msg + '</a></li>');
141          }, this);
142          this.getMsgEl().update(msg+'</ul>');
143         }else{
144             this.getMsgEl().update('');
145         }
146         // reset msgEl size
147         this.getMsgEl().setSize('auto', 'auto');
148     },
149     
150     // private
151     getMsgEl : function(){
152         if(!this.msgEl){
153             this.msgEl = Ext.core.DomHelper.append(Ext.getBody(), {
154                 cls: this.errorListCls
155             }, true);
156             this.msgEl.hide();
157             this.msgEl.on('click', function(e){
158                 var t = e.getTarget('li', 10, true);
159                 if(t){
160                     Ext.getCmp(t.id.split('x-err-')[1]).focus();
161                     this.hideErrors();
162                 }
163             }, this, {stopEvent:true}); // prevent anchor click navigation
164         }
165         return this.msgEl;
166     },
167     
168     // private
169     showErrors : function(){
170         this.updateErrorList();
171         this.getMsgEl().alignTo(this.statusBar.getEl(), this.listAlign).slideIn('b', {duration: 300, easing:'easeOut'});
172         this.statusBar.setText(this.hideText);
173         this.formPanel.el.on('click', this.hideErrors, this, {single:true}); // hide if the user clicks directly into the form
174     },
175     
176     // private
177     hideErrors : function(){
178         var el = this.getMsgEl();
179         if(el.isVisible()){
180          el.slideOut('b', {duration: 300, easing:'easeIn'});
181          this.statusBar.setText(this.showText);
182         }
183         this.formPanel.el.un('click', this.hideErrors, this);
184     },
185     
186     // private
187     onStatusClick : function(){
188         if(this.getMsgEl().isVisible()){
189             this.hideErrors();
190         }else if(this.errors.getCount() > 0){
191             this.showErrors();
192         }
193     }
194 });