Ext.ux.Wizard.Card.js (6928B)
1 /** 2 * Licensed under GNU LESSER GENERAL PUBLIC LICENSE Version 3 3 * 4 * @author Thorsten Suckow-Homberg <ts@siteartwork.de> 5 * @url http://www.siteartwork.de/wizardcomponent 6 */ 7 8 /** 9 * @class Ext.ux.Wiz.Card 10 * @extends Ext.FormPanel 11 * 12 * A specific {@link Ext.FormPanel} that can be used as a card in a 13 * {@link Ext.ux.Wiz}-component. An instance of this card does only work properly 14 * if used in a panel that uses a {@see Ext.layout.CardLayout}-layout. 15 * 16 * @constructor 17 * @param {Object} config The config object 18 */ 19 Ext.define('Ext.ux.wizard.Card', { 20 extend: 'Ext.form.Panel', 21 cardTitle: '', 22 cls: 'ux-wiz-card', 23 24 /** 25 * @cfg {Boolean} header "True" to create the header element. Defaults to 26 * "false". See {@link Ext.form.FormPanel#header} 27 */ 28 header: false, 29 30 /** 31 * @cfg {Strting} hideMode Hidemode of this component. Defaults to "offsets". 32 * See {@link Ext.form.FormPanel#hideMode} 33 */ 34 hideMode: 'display', 35 36 initComponent: function () { 37 38 this.cardTitle = this.title; 39 this.title = (this.showTitle ? '<span style="' + this.titleStyle + '" class="' + this.titleCls + '" >' + this.title + '</span>' : ''); 40 41 if (this.showTitle) { 42 this.header = true; 43 } 44 45 this.dockedItems = [{ 46 xtype: 'container', 47 xtype: 'toolbar', 48 dock: 'bottom', 49 ui: 'footer', 50 layout: { 51 type: 'hbox', 52 align: 'middle' 53 }, 54 padding: '10 10 5', 55 56 items: [{ 57 xtype: 'component', 58 // id: 'formErrorState', 59 errorpanel: true, 60 baseCls: 'form-error-state', 61 flex: 1, 62 validText: this.validText, 63 invalidText: this.invalidText || 'Error/s detected. Please modify...', 64 tipTpl: Ext.create('Ext.XTemplate', '<ul><tpl for="."><li><span class="field-name">{name}</span>: <span class="error">{error}</span></li></tpl></ul>'), 65 66 getTip: function () { 67 var tip = this.tip; 68 if (!tip) { 69 tip = this.tip = Ext.widget('tooltip', { 70 target: this.el, 71 title: 'Error Details:', 72 autoHide: true, 73 anchor: 'top', 74 mouseOffset: [-11, -2], 75 closable: true, 76 constrainPosition: false, 77 cls: 'errors-tip' 78 }); 79 tip.show(); 80 } 81 return tip; 82 }, 83 84 setErrors: function (errors) { 85 var me = this, 86 baseCls = me.baseCls, 87 tip = me.getTip(); 88 89 errors = Ext.Array.from(errors); 90 91 // Update CSS class and tooltip content 92 if (errors.length) { 93 me.addCls(baseCls + '-invalid'); 94 me.removeCls(baseCls + '-valid'); 95 me.update(me.invalidText); 96 tip.setDisabled(false); 97 tip.update(me.tipTpl.apply(errors)); 98 tip.show(); 99 } else { 100 me.addCls(baseCls + '-valid'); 101 me.removeCls(baseCls + '-invalid'); 102 me.update(me.validText); 103 tip.setDisabled(true); 104 tip.hide(); 105 } 106 } 107 }] 108 }]; 109 110 this.callParent(); 111 112 }, 113 114 // -------- helper 115 isValid: function () { 116 117 return !this.getForm().isDirty(); 118 }, 119 120 // -------- overrides 121 122 /** 123 * Overrides parent implementation since we allow to add any element 124 * in this component which must not be neccessarily be a form-element. 125 * So before a call to "isValid()" is about to be made, this implementation 126 * checks first if the specific item sitting in this component has a method "isValid" - if it 127 * does not exists, it will be added on the fly. 128 */ 129 bindHandler: function () { 130 131 Ext.each(this.form.items, function (f) { 132 if (!f.isValid) { 133 f.isValid = Ext.emptyFn; 134 } 135 }); 136 }, 137 138 /* 139 * Listen for validity change on the entire form and update the combined error icon 140 */ 141 listeners: { 142 fieldvaliditychange: function () { 143 this.updateErrorState(); 144 }, 145 fielderrorchange: function () { 146 this.updateErrorState(); 147 } 148 }, 149 150 updateErrorState: function () { 151 var me = this, 152 errorCmp, fields, errors; 153 154 if (me.hasBeenDirty || me.getForm().isDirty()) { //prevents showing global error when form first loads 155 errorCmp = me.down('component[errorpanel]'); 156 fields = me.getForm().getFields(); 157 errors = []; 158 fields.each(function (field) { 159 Ext.Array.forEach(field.getErrors(), function (error) { 160 errors.push({ name: field.getFieldLabel(), error: error }); 161 }); 162 }); 163 errorCmp.setErrors(errors); 164 me.hasBeenDirty = true; 165 } 166 }, 167 168 /** 169 * Overrides parent implementation. This is needed because in case 170 * this method uses "monitorValid=true", the method "startMonitoring" must 171 * not be called, until the "show"-event of this card fires. 172 */ 173 initEvents: function () { 174 var old = this.monitorValid; 175 this.monitorValid = false; 176 this.callParent(); 177 this.monitorValid = old; 178 }, 179 180 // -------- listener 181 /** 182 * Checks wether the beforecardhide-event may be triggered. 183 */ 184 bubbleBeforeHideEvent: function () { 185 var ly = this.ownerCt.layout; 186 var activeItem = ly.activeItem; 187 188 if (activeItem && activeItem.id === this.id) { 189 //return this.fireEvent('beforedeactivate', this); 190 } 191 192 return true; 193 }, 194 195 /** 196 * Stops monitoring the form elements in this component when the 197 * 'hide'-event gets fired. 198 */ 199 onCardHide: function () { 200 if (this.monitorValid) { 201 this.stopMonitoring(); 202 } 203 }, 204 205 /** 206 * Starts monitoring the form elements in this component when the 207 * 'show'-event gets fired. 208 */ 209 onCardShow: function () { 210 if (this.monitorValid) { 211 this.startMonitoring(); 212 } 213 }, 214 215 216 /** 217 * startMonitoring he form elements 218 * 219 */ 220 startMonitoring: function () { 221 this.startPolling(); 222 }, 223 224 225 /** 226 * startMonitoring he form elements 227 * 228 */ 229 stopMonitoring: function () { 230 this.stopPolling(); 231 } 232 233 });