ValidationStatus.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. * @cfg {String} showText
  33. * The {@link #text} value to be applied when there is a form validation error.
  34. * Defaults to <tt>'The form has errors (click for details...)'</tt>.
  35. */
  36. showText : 'The form has errors (click for details...)',
  37. /**
  38. * @cfg {String} showText
  39. * The {@link #text} value to display when the error list is displayed.
  40. * Defaults to <tt>'Click again to hide the error list'</tt>.
  41. */
  42. hideText : 'Click again to hide the error list',
  43. /**
  44. * @cfg {String} submitText
  45. * The {@link #text} value to be applied when the form is being submitted.
  46. * Defaults to <tt>'Saving...'</tt>.
  47. */
  48. submitText : 'Saving...',
  49. // private
  50. init : function(sb){
  51. sb.on('render', function(){
  52. this.statusBar = sb;
  53. this.monitor = true;
  54. this.errors = Ext.create('Ext.util.MixedCollection');
  55. this.listAlign = (sb.statusAlign === 'right' ? 'br-tr?' : 'bl-tl?');
  56. if (this.form) {
  57. this.formPanel = Ext.getCmp(this.form);
  58. this.basicForm = this.formPanel.getForm();
  59. this.startMonitoring();
  60. this.basicForm.on('beforeaction', function(f, action){
  61. if(action.type === 'submit'){
  62. // Ignore monitoring while submitting otherwise the field validation
  63. // events cause the status message to reset too early
  64. this.monitor = false;
  65. }
  66. }, this);
  67. var startMonitor = function(){
  68. this.monitor = true;
  69. };
  70. this.basicForm.on('actioncomplete', startMonitor, this);
  71. this.basicForm.on('actionfailed', startMonitor, this);
  72. }
  73. }, this, {single:true});
  74. sb.on({
  75. scope: this,
  76. afterlayout:{
  77. single: true,
  78. fn: function(){
  79. // Grab the statusEl after the first layout.
  80. sb.statusEl.getEl().on('click', this.onStatusClick, this, {buffer:200});
  81. }
  82. },
  83. beforedestroy:{
  84. single: true,
  85. fn: this.onDestroy
  86. }
  87. });
  88. },
  89. // private
  90. startMonitoring : function() {
  91. this.basicForm.getFields().each(function(f){
  92. f.on('validitychange', this.onFieldValidation, this);
  93. }, this);
  94. },
  95. // private
  96. stopMonitoring : function(){
  97. this.basicForm.getFields().each(function(f){
  98. f.un('validitychange', this.onFieldValidation, this);
  99. }, this);
  100. },
  101. // private
  102. onDestroy : function(){
  103. this.stopMonitoring();
  104. this.statusBar.statusEl.un('click', this.onStatusClick, this);
  105. this.callParent(arguments);
  106. },
  107. // private
  108. onFieldValidation : function(f, isValid){
  109. if (!this.monitor) {
  110. return false;
  111. }
  112. var msg = f.getErrors()[0];
  113. if (msg) {
  114. this.errors.add(f.id, {field:f, msg:msg});
  115. } else {
  116. this.errors.removeAtKey(f.id);
  117. }
  118. this.updateErrorList();
  119. if(this.errors.getCount() > 0) {
  120. if(this.statusBar.getText() !== this.showText){
  121. this.statusBar.setStatus({text:this.showText, iconCls:this.errorIconCls});
  122. }
  123. }else{
  124. this.statusBar.clearStatus().setIcon(this.validIconCls);
  125. }
  126. },
  127. // private
  128. updateErrorList : function(){
  129. if(this.errors.getCount() > 0){
  130. var msg = '<ul>';
  131. this.errors.each(function(err){
  132. msg += ('<li id="x-err-'+ err.field.id +'"><a href="#">' + err.msg + '</a></li>');
  133. }, this);
  134. this.getMsgEl().update(msg+'</ul>');
  135. }else{
  136. this.getMsgEl().update('');
  137. }
  138. // reset msgEl size
  139. this.getMsgEl().setSize('auto', 'auto');
  140. },
  141. // private
  142. getMsgEl : function(){
  143. if(!this.msgEl){
  144. this.msgEl = Ext.core.DomHelper.append(Ext.getBody(), {
  145. cls: this.errorListCls
  146. }, true);
  147. this.msgEl.hide();
  148. this.msgEl.on('click', function(e){
  149. var t = e.getTarget('li', 10, true);
  150. if(t){
  151. Ext.getCmp(t.id.split('x-err-')[1]).focus();
  152. this.hideErrors();
  153. }
  154. }, this, {stopEvent:true}); // prevent anchor click navigation
  155. }
  156. return this.msgEl;
  157. },
  158. // private
  159. showErrors : function(){
  160. this.updateErrorList();
  161. this.getMsgEl().alignTo(this.statusBar.getEl(), this.listAlign).slideIn('b', {duration: 300, easing:'easeOut'});
  162. this.statusBar.setText(this.hideText);
  163. this.formPanel.el.on('click', this.hideErrors, this, {single:true}); // hide if the user clicks directly into the form
  164. },
  165. // private
  166. hideErrors : function(){
  167. var el = this.getMsgEl();
  168. if(el.isVisible()){
  169. el.slideOut('b', {duration: 300, easing:'easeIn'});
  170. this.statusBar.setText(this.showText);
  171. }
  172. this.formPanel.el.un('click', this.hideErrors, this);
  173. },
  174. // private
  175. onStatusClick : function(){
  176. if(this.getMsgEl().isVisible()){
  177. this.hideErrors();
  178. }else if(this.errors.getCount() > 0){
  179. this.showErrors();
  180. }
  181. }
  182. });