]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * The Form panel presents a set of form fields and provides convenient ways to load and save data. Usually a form\r | |
3 | * panel just contains the set of fields you want to display, ordered inside the items configuration like this:\r | |
4 | *\r | |
5 | * @example\r | |
6 | * var form = Ext.create('Ext.form.Panel', {\r | |
7 | * fullscreen: true,\r | |
8 | * items: [\r | |
9 | * {\r | |
10 | * xtype: 'textfield',\r | |
11 | * name: 'name',\r | |
12 | * label: 'Name'\r | |
13 | * },\r | |
14 | * {\r | |
15 | * xtype: 'emailfield',\r | |
16 | * name: 'email',\r | |
17 | * label: 'Email'\r | |
18 | * },\r | |
19 | * {\r | |
20 | * xtype: 'passwordfield',\r | |
21 | * name: 'password',\r | |
22 | * label: 'Password'\r | |
23 | * }\r | |
24 | * ]\r | |
25 | * });\r | |
26 | *\r | |
27 | * Here we just created a simple form panel which could be used as a registration form to sign up to your service. We\r | |
28 | * added a plain {@link Ext.field.Text text field} for the user's Name, an {@link Ext.field.Email email field} and\r | |
29 | * finally a {@link Ext.field.Password password field}. In each case we provided a {@link Ext.field.Field#name name}\r | |
30 | * config on the field so that we can identify it later on when we load and save data on the form.\r | |
31 | *\r | |
32 | * ##Loading data\r | |
33 | *\r | |
34 | * Using the form we created above, we can load data into it in a few different ways, the easiest is to use\r | |
35 | * {@link #setValues}:\r | |
36 | *\r | |
37 | * form.setValues({\r | |
38 | * name: 'Peter',\r | |
39 | * email: 'peter.venkman@gb.com',\r | |
40 | * password: 'secret'\r | |
41 | * });\r | |
42 | *\r | |
43 | * It's also easy to load {@link Ext.data.Model Model} instances into a form - let's say we have a User model and want\r | |
44 | * to load a particular instance into our form:\r | |
45 | *\r | |
46 | * Ext.define('MyApp.model.User', {\r | |
47 | * extend: 'Ext.data.Model',\r | |
48 | * config: {\r | |
49 | * fields: ['name', 'email', 'password']\r | |
50 | * }\r | |
51 | * });\r | |
52 | *\r | |
53 | * var ed = Ext.create('MyApp.model.User', {\r | |
54 | * name: 'Peter',\r | |
55 | * email: 'peter.venkman@gb.com',\r | |
56 | * password: 'secret'\r | |
57 | * });\r | |
58 | *\r | |
59 | * form.setRecord(ed);\r | |
60 | *\r | |
61 | * ##Retrieving form data\r | |
62 | *\r | |
63 | * Getting data out of the form panel is simple and is usually achieve via the {@link #getValues} method:\r | |
64 | *\r | |
65 | * var values = form.getValues();\r | |
66 | *\r | |
67 | * //values now looks like this:\r | |
68 | * {\r | |
69 | * name: 'Peter',\r | |
70 | * email: 'peter.venkman@gb.com',\r | |
71 | * password: 'secret'\r | |
72 | * }\r | |
73 | *\r | |
74 | * It's also possible to listen to the change events on individual fields to get more timely notification of changes\r | |
75 | * that the user is making. Here we expand on the example above with the User model, updating the model as soon as\r | |
76 | * any of the fields are changed:\r | |
77 | *\r | |
78 | * var form = Ext.create('Ext.form.Panel', {\r | |
79 | * listeners: {\r | |
80 | * '> field': {\r | |
81 | * change: function(field, newValue, oldValue) {\r | |
82 | * ed.set(field.getName(), newValue);\r | |
83 | * }\r | |
84 | * }\r | |
85 | * },\r | |
86 | * items: [\r | |
87 | * {\r | |
88 | * xtype: 'textfield',\r | |
89 | * name: 'name',\r | |
90 | * label: 'Name'\r | |
91 | * },\r | |
92 | * {\r | |
93 | * xtype: 'emailfield',\r | |
94 | * name: 'email',\r | |
95 | * label: 'Email'\r | |
96 | * },\r | |
97 | * {\r | |
98 | * xtype: 'passwordfield',\r | |
99 | * name: 'password',\r | |
100 | * label: 'Password'\r | |
101 | * }\r | |
102 | * ]\r | |
103 | * });\r | |
104 | *\r | |
105 | * The above attached a listener to the {@link Ext.field.Text#change change} event of each form\r | |
106 | * field that is a direct child of the form panel. Our listener gets the name of the field that fired the change event,\r | |
107 | * and updates our {@link Ext.data.Model Model} instance with the new value. For example, changing the email field\r | |
108 | * in the form will update the Model's email field.\r | |
109 | *\r | |
110 | * ##Submitting forms\r | |
111 | *\r | |
112 | * There are a few ways to submit form data. In our example above we have a Model instance that we have updated, giving\r | |
113 | * us the option to use the Model's {@link Ext.data.Model#save save} method to persist the changes back to our server,\r | |
114 | * without using a traditional form submission. Alternatively, we can send a normal browser form submit using the\r | |
115 | * {@link #method} method:\r | |
116 | *\r | |
117 | * form.submit({\r | |
118 | * url: 'url/to/submit/to',\r | |
119 | * method: 'POST',\r | |
120 | * success: function() {\r | |
121 | * alert('form submitted successfully!');\r | |
122 | * }\r | |
123 | * });\r | |
124 | *\r | |
125 | * In this case we provided the `url` to submit the form to inside the submit call - alternatively you can just set the\r | |
126 | * {@link #url} configuration when you create the form. We can specify other parameters (see {@link #method} for a\r | |
127 | * full list), including callback functions for success and failure, which are called depending on whether or not the\r | |
128 | * form submission was successful. These functions are usually used to take some action in your app after your data\r | |
129 | * has been saved to the server side.\r | |
130 | */\r | |
131 | Ext.define('Ext.form.Panel', {\r | |
132 | alternateClassName: 'Ext.form.FormPanel',\r | |
133 | extend : 'Ext.Panel',\r | |
134 | xtype : 'formpanel',\r | |
135 | requires: ['Ext.XTemplate', 'Ext.field.Checkbox', 'Ext.Ajax'],\r | |
136 | \r | |
137 | /**\r | |
138 | * @event submit\r | |
139 | * @preventable\r | |
140 | * Fires upon successful (Ajax-based) form submission.\r | |
141 | * @param {Ext.form.Panel} this This FormPanel.\r | |
142 | * @param {Object} result The result object as returned by the server.\r | |
143 | * @param {Ext.event.Event} e The event object.\r | |
144 | */\r | |
145 | \r | |
146 | /**\r | |
147 | * @event beforesubmit\r | |
148 | * @preventable\r | |
149 | * Fires immediately preceding any Form submit action.\r | |
150 | * Implementations may adjust submitted form values or options prior to execution.\r | |
151 | * A return value of `false` from this listener will abort the submission\r | |
152 | * attempt (regardless of `standardSubmit` configuration).\r | |
153 | * @param {Ext.form.Panel} this This FormPanel.\r | |
154 | * @param {Object} values A hash collection of the qualified form values about to be submitted.\r | |
155 | * @param {Object} options Submission options hash (only available when `standardSubmit` is `false`).\r | |
156 | * @param {Ext.event.Event} e The event object if the form was submitted via a HTML5 form submit event.\r | |
157 | */\r | |
158 | \r | |
159 | /**\r | |
160 | * @event exception\r | |
161 | * Fires when either the Ajax HTTP request reports a failure OR the server returns a `success:false`\r | |
162 | * response in the result payload.\r | |
163 | * @param {Ext.form.Panel} this This FormPanel.\r | |
164 | * @param {Object} result Either a failed Ext.data.Connection request object or a failed (logical) server.\r | |
165 | * response payload.\r | |
166 | */\r | |
167 | \r | |
168 | config: {\r | |
169 | /**\r | |
170 | * @cfg {String} baseCls\r | |
171 | * @inheritdoc\r | |
172 | */\r | |
173 | baseCls: Ext.baseCSSPrefix + 'form',\r | |
174 | \r | |
175 | /**\r | |
176 | * @cfg {Boolean} standardSubmit\r | |
177 | * Whether or not we want to perform a standard form submit.\r | |
178 | * @accessor\r | |
179 | */\r | |
180 | standardSubmit: false,\r | |
181 | \r | |
182 | /**\r | |
183 | * @cfg {String} url\r | |
184 | * The default url for submit actions.\r | |
185 | * @accessor\r | |
186 | */\r | |
187 | url: null,\r | |
188 | \r | |
189 | /**\r | |
190 | * @cfg {String} enctype\r | |
191 | * The enctype attribute for the form, specifies how the form should be encoded when submitting\r | |
192 | */\r | |
193 | enctype: null,\r | |
194 | \r | |
195 | /**\r | |
196 | * @cfg {Object} baseParams\r | |
197 | * Optional hash of params to be sent (when `standardSubmit` configuration is `false`) on every submit.\r | |
198 | * @accessor\r | |
199 | */\r | |
200 | baseParams: null,\r | |
201 | \r | |
202 | /**\r | |
203 | * @cfg {Object} submitOnAction\r | |
204 | * When this is set to `true`, the form will automatically submit itself whenever the `action`\r | |
205 | * event fires on a field in this form. The action event usually fires whenever you press\r | |
206 | * go or enter inside a textfield.\r | |
207 | * @accessor\r | |
208 | */\r | |
209 | submitOnAction: false,\r | |
210 | \r | |
211 | /**\r | |
212 | * @cfg {Ext.data.Model} record The model instance of this form. Can by dynamically set at any time.\r | |
213 | * @accessor\r | |
214 | */\r | |
215 | record: null,\r | |
216 | \r | |
217 | /**\r | |
218 | * @cfg {String} method\r | |
219 | * The method which this form will be submitted. `post` or `get`.\r | |
220 | */\r | |
221 | method: 'post',\r | |
222 | \r | |
223 | /**\r | |
224 | * @inheritdoc\r | |
225 | */\r | |
226 | scrollable: true,\r | |
227 | \r | |
228 | /**\r | |
229 | * @cfg {Boolean} trackResetOnLoad\r | |
230 | * If set to true, {@link #reset}() resets to the last loaded or {@link #setValues}() data instead of\r | |
231 | * when the form was first created.\r | |
232 | */\r | |
233 | trackResetOnLoad:false,\r | |
234 | \r | |
235 | /**\r | |
236 | * @cfg {Object} api\r | |
237 | * If specified, load and submit actions will be loaded and submitted via Ext Direct. Methods which have been imported by\r | |
238 | * {@link Ext.direct.Manager} can be specified here to load and submit forms. API methods may also be\r | |
239 | * specified as strings and will be parsed into the actual functions when the first submit or load has occurred. Such as the following:\r | |
240 | *\r | |
241 | * api: {\r | |
242 | * load: App.ss.MyProfile.load,\r | |
243 | * submit: App.ss.MyProfile.submit\r | |
244 | * }\r | |
245 | *\r | |
246 | * api: {\r | |
247 | * load: 'App.ss.MyProfile.load',\r | |
248 | * submit: 'App.ss.MyProfile.submit'\r | |
249 | * }\r | |
250 | *\r | |
251 | * Load actions can use {@link #paramOrder} or {@link #paramsAsHash} to customize how the load method\r | |
252 | * is invoked. Submit actions will always use a standard form submit. The `formHandler` configuration\r | |
253 | * (see Ext.direct.RemotingProvider#action) must be set on the associated server-side method which has\r | |
254 | * been imported by {@link Ext.direct.Manager}.\r | |
255 | */\r | |
256 | api: null,\r | |
257 | \r | |
258 | /**\r | |
259 | * @cfg {String/String[]} paramOrder\r | |
260 | * A list of params to be executed server side. Only used for the {@link #api} `load`\r | |
261 | * configuration.\r | |
262 | *\r | |
263 | * Specify the params in the order in which they must be executed on the\r | |
264 | * server-side as either (1) an Array of String values, or (2) a String of params\r | |
265 | * delimited by either whitespace, comma, or pipe. For example,\r | |
266 | * any of the following would be acceptable:\r | |
267 | *\r | |
268 | * paramOrder: ['param1','param2','param3']\r | |
269 | * paramOrder: 'param1 param2 param3'\r | |
270 | * paramOrder: 'param1,param2,param3'\r | |
271 | * paramOrder: 'param1|param2|param'\r | |
272 | */\r | |
273 | paramOrder: null,\r | |
274 | \r | |
275 | /**\r | |
276 | * @cfg {Boolean} paramsAsHash\r | |
277 | * Only used for the {@link #api} `load` configuration. If true, parameters will be sent as a\r | |
278 | * single hash collection of named arguments. Providing a {@link #paramOrder} nullifies this\r | |
279 | * configuration.\r | |
280 | */\r | |
281 | paramsAsHash: null,\r | |
282 | \r | |
283 | /**\r | |
284 | * @cfg {Number} timeout\r | |
285 | * Timeout for form actions in seconds.\r | |
286 | */\r | |
287 | timeout: 30,\r | |
288 | \r | |
289 | /**\r | |
290 | * @cfg {Boolean} multipartDetection\r | |
291 | * If this is enabled the form will automatically detect the need to use 'multipart/form-data' during submission.\r | |
292 | */\r | |
293 | multipartDetection: true,\r | |
294 | \r | |
295 | /**\r | |
296 | * @cfg {Boolean} enableSubmissionForm\r | |
297 | * The submission form is generated but never added to the dom. It is a submittable version of your form panel, allowing for fields\r | |
298 | * that are not simple textfields to be properly submitted to servers. It will also send values that are easier to parse\r | |
299 | * with server side code.\r | |
300 | *\r | |
301 | * If this is false we will attempt to subject the raw form inside the form panel.\r | |
302 | */\r | |
303 | enableSubmissionForm: true\r | |
304 | },\r | |
305 | \r | |
306 | getElementConfig: function() {\r | |
307 | var config = this.callParent();\r | |
308 | config.tag = "form";\r | |
309 | // Added a submit input for standard form submission. This cannot have "display: none;" or it will not work\r | |
310 | config.children.push({\r | |
311 | tag: 'input',\r | |
312 | type: 'submit',\r | |
313 | style: 'visibility: hidden; width: 0; height: 0; position: absolute; right: 0; bottom: 0;'\r | |
314 | });\r | |
315 | \r | |
316 | return config;\r | |
317 | },\r | |
318 | \r | |
319 | /**\r | |
320 | * @private\r | |
321 | */\r | |
322 | initialize: function() {\r | |
323 | var me = this;\r | |
324 | me.callParent();\r | |
325 | \r | |
326 | me.element.on({\r | |
327 | submit: 'onSubmit',\r | |
328 | scope : me\r | |
329 | });\r | |
330 | },\r | |
331 | \r | |
332 | applyEnctype: function(newValue) {\r | |
333 | var form = this.element.dom || null;\r | |
334 | if(form) {\r | |
335 | if (newValue) {\r | |
336 | form.setAttribute("enctype", newValue);\r | |
337 | } else {\r | |
338 | form.setAttribute("enctype");\r | |
339 | }\r | |
340 | }\r | |
341 | },\r | |
342 | \r | |
343 | updateRecord: function(newRecord) {\r | |
344 | var fields, values, name;\r | |
345 | \r | |
346 | if (newRecord) {\r | |
347 | values = this.getValues();\r | |
348 | for (name in values) {\r | |
349 | if (values.hasOwnProperty(name) && newRecord.getField(name)) {\r | |
350 | newRecord.set(name, values[name]);\r | |
351 | }\r | |
352 | }\r | |
353 | }\r | |
354 | return this;\r | |
355 | },\r | |
356 | \r | |
357 | /**\r | |
358 | * Loads matching fields from a model instance into this form.\r | |
359 | * @param {Ext.data.Model} record The model instance.\r | |
360 | * @return {Ext.form.Panel} This form.\r | |
361 | */\r | |
362 | setRecord: function(record) {\r | |
363 | var me = this;\r | |
364 | \r | |
365 | if (record && record.data) {\r | |
366 | me.setValues(record.data);\r | |
367 | }\r | |
368 | \r | |
369 | me._record = record;\r | |
370 | \r | |
371 | return this;\r | |
372 | },\r | |
373 | \r | |
374 | /**\r | |
375 | * @private\r | |
376 | */\r | |
377 | onSubmit: function(e) {\r | |
378 | var me = this;\r | |
379 | if (e && !me.getStandardSubmit()) {\r | |
380 | e.stopEvent();\r | |
381 | } else {\r | |
382 | this.submit(null, e);\r | |
383 | }\r | |
384 | },\r | |
385 | \r | |
386 | updateSubmitOnAction: function(newSubmitOnAction) {\r | |
387 | if (newSubmitOnAction) {\r | |
388 | this.on({\r | |
389 | action: 'onFieldAction',\r | |
390 | scope: this\r | |
391 | });\r | |
392 | } else {\r | |
393 | this.un({\r | |
394 | action: 'onFieldAction',\r | |
395 | scope: this\r | |
396 | });\r | |
397 | }\r | |
398 | },\r | |
399 | \r | |
400 | /**\r | |
401 | * @private\r | |
402 | */\r | |
403 | onFieldAction: function(field) {\r | |
404 | if (this.getSubmitOnAction()) {\r | |
405 | field.blur();\r | |
406 | this.submit();\r | |
407 | }\r | |
408 | },\r | |
409 | \r | |
410 | /**\r | |
411 | * Performs a Ajax-based submission of form values (if {@link #standardSubmit} is false) or otherwise\r | |
412 | * executes a standard HTML Form submit action.\r | |
413 | *\r | |
414 | * **Notes**\r | |
415 | *\r | |
416 | * 1. Only the first parameter is implemented. Put all other parameters inside the first\r | |
417 | * parameter:\r | |
418 | *\r | |
419 | * submit({params: "" ,headers: "" etc.})\r | |
420 | *\r | |
421 | * 2. Submit example:\r | |
422 | *\r | |
423 | * myForm.submit({\r | |
424 | * url: 'PostMyData/To',\r | |
425 | * method: 'Post',\r | |
426 | * success: function() { Ext.Msg.alert("success"); },\r | |
427 | * failure: function() { Ext.Msg.alert("error"); }\r | |
428 | * });\r | |
429 | *\r | |
430 | * 3. Parameters and values only submit for a POST and not for a GET.\r | |
431 | *\r | |
432 | * @param {Object} options\r | |
433 | * The configuration when submitting this form.\r | |
434 | *\r | |
435 | * The following are the configurations when submitting via Ajax only:\r | |
436 | *\r | |
437 | * @param {String} options.url\r | |
438 | * The url for the action (defaults to the form's {@link #url}).\r | |
439 | *\r | |
440 | * @param {String} options.method\r | |
441 | * The form method to use (defaults to the form's {@link #method}, or POST if not defined).\r | |
442 | *\r | |
443 | * @param {Object} options.headers\r | |
444 | * Request headers to set for the action.\r | |
445 | *\r | |
446 | * @param {Boolean} [options.autoAbort=false]\r | |
447 | * `true` to abort any pending Ajax request prior to submission.\r | |
448 | * __Note:__ Has no effect when `{@link #standardSubmit}` is enabled.\r | |
449 | *\r | |
450 | * @param {Number} options.timeout\r | |
451 | * The number is seconds the loading will timeout in.\r | |
452 | *\r | |
453 | * The following are the configurations when loading via Ajax or Direct:\r | |
454 | *\r | |
455 | * @param {String/Object} options.params\r | |
456 | * The params to pass when submitting this form (defaults to this forms {@link #baseParams}).\r | |
457 | * Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.\r | |
458 | *\r | |
459 | * @param {Boolean} [options.submitDisabled=false]\r | |
460 | * `true` to submit all fields regardless of disabled state.\r | |
461 | * __Note:__ Has no effect when `{@link #standardSubmit}` is enabled.\r | |
462 | *\r | |
463 | * @param {String/Object} [options.waitMsg]\r | |
464 | * If specified, the value which is passed to the loading {@link #masked mask}. See {@link #masked} for\r | |
465 | * more information.\r | |
466 | *\r | |
467 | * @param {Function} options.success\r | |
468 | * The callback that will be invoked after a successful response. A response is successful if\r | |
469 | * a response is received from the server and is a JSON object where the `success` property is set\r | |
470 | * to `true`, `{"success": true}`.\r | |
471 | *\r | |
472 | * The function is passed the following parameters and can be used for submitting via Ajax or Direct:\r | |
473 | *\r | |
474 | * @param {Ext.form.Panel} options.success.form\r | |
475 | * The {@link Ext.form.Panel} that requested the action.\r | |
476 | *\r | |
477 | * @param {Object/Ext.direct.Event} options.success.result\r | |
478 | * The result object returned by the server as a result of the submit request. If the submit is sent using Ext Direct,\r | |
479 | * this will return the {@link Ext.direct.Event} instance, otherwise will return an Object.\r | |
480 | *\r | |
481 | * @param {Object} options.success.data\r | |
482 | * The parsed data returned by the server.\r | |
483 | *\r | |
484 | * @param {Function} options.failure\r | |
485 | * The callback that will be invoked after a failed transaction attempt.\r | |
486 | *\r | |
487 | * The function is passed the following parameters and can be used for submitting via Ajax or Direct:\r | |
488 | *\r | |
489 | * @param {Ext.form.Panel} options.failure.form\r | |
490 | * The {@link Ext.form.Panel} that requested the submit.\r | |
491 | *\r | |
492 | * @param {Ext.form.Panel} options.failure.result\r | |
493 | * The failed response or result object returned by the server which performed the operation.\r | |
494 | *\r | |
495 | * @param {Object} options.success.data\r | |
496 | * The parsed data returned by the server.\r | |
497 | *\r | |
498 | * @param {Object} options.scope\r | |
499 | * The scope in which to call the callback functions (The `this` reference for the callback functions).\r | |
500 | *\r | |
501 | * @return {Ext.data.Connection} The request object if the {@link #standardSubmit} config is false.\r | |
502 | * If the standardSubmit config is true, then the return value is undefined.\r | |
503 | */\r | |
504 | submit: function(options, e) {\r | |
505 | options = options || {};\r | |
506 | \r | |
507 | var me = this,\r | |
508 | formValues = me.getValues(me.getStandardSubmit() || !options.submitDisabled),\r | |
509 | form = me.element.dom || {};\r | |
510 | \r | |
511 | if(this.getEnableSubmissionForm()) {\r | |
512 | form = this.createSubmissionForm(form, formValues);\r | |
513 | }\r | |
514 | \r | |
515 | options = Ext.apply({\r | |
516 | url : me.getUrl() || form.action,\r | |
517 | submit: false,\r | |
518 | form: form,\r | |
519 | method : me.getMethod() || form.method || 'post',\r | |
520 | autoAbort : false,\r | |
521 | params : null,\r | |
522 | waitMsg : null,\r | |
523 | headers : null,\r | |
524 | success : null,\r | |
525 | failure : null\r | |
526 | }, options || {});\r | |
527 | \r | |
528 | return me.fireAction('beforesubmit', [me, formValues, options, e], 'doBeforeSubmit', null, null, 'after');\r | |
529 | },\r | |
530 | \r | |
531 | createSubmissionForm: function(form, values) {\r | |
532 | var fields = this.getFields(),\r | |
533 | name, input, field, fileinputElement, inputComponent;\r | |
534 | \r | |
535 | if(form.nodeType === 1) {\r | |
536 | form = form.cloneNode(false);\r | |
537 | \r | |
538 | for (name in values) {\r | |
539 | input = document.createElement("input");\r | |
540 | input.setAttribute("type", "text");\r | |
541 | input.setAttribute("name", name);\r | |
542 | input.setAttribute("value", values[name]);\r | |
543 | form.appendChild(input);\r | |
544 | }\r | |
545 | }\r | |
546 | \r | |
547 | for (name in fields) {\r | |
548 | if (fields.hasOwnProperty(name)) {\r | |
549 | field = fields[name];\r | |
550 | if(field.isFile) {\r | |
551 | if(!form.$fileswap) form.$fileswap = [];\r | |
552 | \r | |
553 | inputComponent = field.getComponent().input;\r | |
554 | fileinputElement = inputComponent.dom;\r | |
555 | input = fileinputElement.cloneNode(true);\r | |
556 | fileinputElement.parentNode.insertBefore(input, fileinputElement.nextSibling);\r | |
557 | form.appendChild(fileinputElement);\r | |
558 | form.$fileswap.push({original: fileinputElement, placeholder: input});\r | |
559 | } else if(field.isPassword) {\r | |
560 | if(field.getComponent().getType !== "password") {\r | |
561 | field.setRevealed(false);\r | |
562 | }\r | |
563 | }\r | |
564 | }\r | |
565 | }\r | |
566 | \r | |
567 | return form;\r | |
568 | },\r | |
569 | \r | |
570 | doBeforeSubmit: function(me, formValues, options) {\r | |
571 | var form = options.form || {},\r | |
572 | multipartDetected = false;\r | |
573 | \r | |
574 | if(this.getMultipartDetection() === true) {\r | |
575 | this.getFieldsAsArray().forEach(function(field) {\r | |
576 | if(field.isFile === true) {\r | |
577 | multipartDetected = true;\r | |
578 | return false;\r | |
579 | }\r | |
580 | });\r | |
581 | \r | |
582 | if(multipartDetected) {\r | |
583 | form.setAttribute("enctype", "multipart/form-data");\r | |
584 | }\r | |
585 | }\r | |
586 | \r | |
587 | if(options.enctype) {\r | |
588 | form.setAttribute("enctype", options.enctype);\r | |
589 | }\r | |
590 | \r | |
591 | if (me.getStandardSubmit()) {\r | |
592 | if (options.url && Ext.isEmpty(form.action)) {\r | |
593 | form.action = options.url;\r | |
594 | }\r | |
595 | \r | |
596 | // Spinner fields must have their components enabled *before* submitting or else the value\r | |
597 | // will not be posted.\r | |
598 | var fields = this.query('spinnerfield'),\r | |
599 | ln = fields.length,\r | |
600 | i, field;\r | |
601 | \r | |
602 | for (i = 0; i < ln; i++) {\r | |
603 | field = fields[i];\r | |
604 | if (!field.getDisabled()) {\r | |
605 | field.getComponent().setDisabled(false);\r | |
606 | }\r | |
607 | }\r | |
608 | \r | |
609 | form.method = (options.method || form.method).toLowerCase();\r | |
610 | form.submit();\r | |
611 | } else {\r | |
612 | var api = me.getApi(),\r | |
613 | url = options.url || me.getUrl(),\r | |
614 | scope = options.scope || me,\r | |
615 | waitMsg = options.waitMsg,\r | |
616 | failureFn = function(response, responseText) {\r | |
617 | if (Ext.isFunction(options.failure)) {\r | |
618 | options.failure.call(scope, me, response, responseText);\r | |
619 | }\r | |
620 | \r | |
621 | me.fireEvent('exception', me, response);\r | |
622 | },\r | |
623 | successFn = function(response, responseText) {\r | |
624 | if (Ext.isFunction(options.success)) {\r | |
625 | options.success.call(options.scope || me, me, response, responseText);\r | |
626 | }\r | |
627 | \r | |
628 | me.fireEvent('submit', me, response);\r | |
629 | },\r | |
630 | submit;\r | |
631 | \r | |
632 | if (options.waitMsg) {\r | |
633 | if (typeof waitMsg === 'string') {\r | |
634 | waitMsg = {\r | |
635 | xtype : 'loadmask',\r | |
636 | message : waitMsg\r | |
637 | };\r | |
638 | }\r | |
639 | \r | |
640 | me.setMasked(waitMsg);\r | |
641 | }\r | |
642 | \r | |
643 | if (api) {\r | |
644 | submit = api.submit;\r | |
645 | \r | |
646 | if (typeof submit === 'string') {\r | |
647 | submit = Ext.direct.Manager.parseMethod(submit);\r | |
648 | \r | |
649 | if (submit) {\r | |
650 | api.submit = submit;\r | |
651 | }\r | |
652 | }\r | |
653 | \r | |
654 | if (submit) {\r | |
655 | return submit(this.element, function(data, response, success) {\r | |
656 | me.setMasked(false);\r | |
657 | \r | |
658 | if (success) {\r | |
659 | if (data.success) {\r | |
660 | successFn(response, data);\r | |
661 | } else {\r | |
662 | failureFn(response, data);\r | |
663 | }\r | |
664 | } else {\r | |
665 | failureFn(response, data);\r | |
666 | }\r | |
667 | }, this);\r | |
668 | }\r | |
669 | } else {\r | |
670 | var request = Ext.merge({},\r | |
671 | {\r | |
672 | url: url,\r | |
673 | timeout: this.getTimeout() * 1000,\r | |
674 | form: form,\r | |
675 | scope: me\r | |
676 | },\r | |
677 | options\r | |
678 | );\r | |
679 | delete request.success;\r | |
680 | delete request.failure;\r | |
681 | \r | |
682 | request.params = Ext.merge(me.getBaseParams() || {}, options.params);\r | |
683 | request.header = Ext.apply(\r | |
684 | {\r | |
685 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'\r | |
686 | },\r | |
687 | options.headers || {}\r | |
688 | );\r | |
689 | request.callback = function(callbackOptions, success, response) {\r | |
690 | var me = this,\r | |
691 | responseText = response.responseText,\r | |
692 | responseXML = response.responseXML,\r | |
693 | statusResult = Ext.data.request.Ajax.parseStatus(response.status, response);\r | |
694 | \r | |
695 | if(form.$fileswap) {\r | |
696 | var original, placeholder;\r | |
697 | Ext.each(form.$fileswap, function(item) {\r | |
698 | original = item.original;\r | |
699 | placeholder = item.placeholder;\r | |
700 | \r | |
701 | placeholder.parentNode.insertBefore(original, placeholder.nextSibling);\r | |
702 | placeholder.parentNode.removeChild(placeholder);\r | |
703 | });\r | |
704 | form.$fileswap = null;\r | |
705 | delete form.$fileswap;\r | |
706 | }\r | |
707 | \r | |
708 | me.setMasked(false);\r | |
709 | \r | |
710 | if(response.success === false) success = false;\r | |
711 | if (success) {\r | |
712 | if (statusResult && responseText && responseText.length === 0) {\r | |
713 | success = true;\r | |
714 | } else {\r | |
715 | if(!Ext.isEmpty(response.responseBytes)) {\r | |
716 | success = statusResult.success;\r | |
717 | }else {\r | |
718 | if(Ext.isString(responseText) && response.request.options.responseType === "text") {\r | |
719 | response.success = true;\r | |
720 | } else if(Ext.isString(responseText)) {\r | |
721 | try {\r | |
722 | response = Ext.decode(responseText);\r | |
723 | }catch (e){\r | |
724 | response.success = false;\r | |
725 | response.error = e;\r | |
726 | response.message = e.message;\r | |
727 | }\r | |
728 | } else if(Ext.isSimpleObject(responseText)) {\r | |
729 | response = responseText;\r | |
730 | Ext.applyIf(response, {success:true});\r | |
731 | }\r | |
732 | \r | |
733 | if(!Ext.isEmpty(responseXML)){\r | |
734 | response.success = true;\r | |
735 | }\r | |
736 | success = !!response.success;\r | |
737 | }\r | |
738 | }\r | |
739 | if (success) {\r | |
740 | successFn(response, responseText);\r | |
741 | } else {\r | |
742 | failureFn(response, responseText);\r | |
743 | }\r | |
744 | }\r | |
745 | else {\r | |
746 | failureFn(response, responseText);\r | |
747 | }\r | |
748 | };\r | |
749 | \r | |
750 | if(Ext.feature.has.XHR2 && request.xhr2) {\r | |
751 | delete request.form;\r | |
752 | var formData = new FormData(form);\r | |
753 | if (request.params) {\r | |
754 | Ext.iterate(request.params, function(name, value) {\r | |
755 | if (Ext.isArray(value)) {\r | |
756 | Ext.each(value, function(v) {\r | |
757 | formData.append(name, v);\r | |
758 | });\r | |
759 | } else {\r | |
760 | formData.append(name, value);\r | |
761 | }\r | |
762 | });\r | |
763 | delete request.params;\r | |
764 | }\r | |
765 | request.data = formData;\r | |
766 | }\r | |
767 | \r | |
768 | return Ext.Ajax.request(request);\r | |
769 | }\r | |
770 | }\r | |
771 | },\r | |
772 | \r | |
773 | /**\r | |
774 | * Performs an Ajax or Ext Direct call to load values for this form.\r | |
775 | *\r | |
776 | * @param {Object} options\r | |
777 | * The configuration when loading this form.\r | |
778 | *\r | |
779 | * The following are the configurations when loading via Ajax only:\r | |
780 | *\r | |
781 | * @param {String} options.url\r | |
782 | * The url for the action (defaults to the form's {@link #url}).\r | |
783 | *\r | |
784 | * @param {String} options.method\r | |
785 | * The form method to use (defaults to the form's {@link #method}, or GET if not defined).\r | |
786 | *\r | |
787 | * @param {Object} options.headers\r | |
788 | * Request headers to set for the action.\r | |
789 | *\r | |
790 | * @param {Number} options.timeout\r | |
791 | * The number is seconds the loading will timeout in.\r | |
792 | *\r | |
793 | * The following are the configurations when loading via Ajax or Direct:\r | |
794 | *\r | |
795 | * @param {Boolean} [options.autoAbort=false]\r | |
796 | * `true` to abort any pending Ajax request prior to loading.\r | |
797 | *\r | |
798 | * @param {String/Object} options.params\r | |
799 | * The params to pass when submitting this form (defaults to this forms {@link #baseParams}).\r | |
800 | * Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.\r | |
801 | *\r | |
802 | * @param {String/Object} [options.waitMsg]\r | |
803 | * If specified, the value which is passed to the loading {@link #masked mask}. See {@link #masked} for\r | |
804 | * more information.\r | |
805 | *\r | |
806 | * @param {Function} options.success\r | |
807 | * The callback that will be invoked after a successful response. A response is successful if\r | |
808 | * a response is received from the server and is a JSON object where the `success` property is set\r | |
809 | * to `true`, `{"success": true}`.\r | |
810 | *\r | |
811 | * The function is passed the following parameters and can be used for loading via Ajax or Direct:\r | |
812 | *\r | |
813 | * @param {Ext.form.Panel} options.success.form\r | |
814 | * The {@link Ext.form.Panel} that requested the load.\r | |
815 | *\r | |
816 | * @param {Object/Ext.direct.Event} options.success.result\r | |
817 | * The result object returned by the server as a result of the load request. If the loading was done via Ext Direct,\r | |
818 | * will return the {@link Ext.direct.Event} instance, otherwise will return an Object.\r | |
819 | *\r | |
820 | * @param {Object} options.success.data\r | |
821 | * The parsed data returned by the server.\r | |
822 | *\r | |
823 | * @param {Function} options.failure\r | |
824 | * The callback that will be invoked after a failed transaction attempt.\r | |
825 | *\r | |
826 | * The function is passed the following parameters and can be used for loading via Ajax or Direct:\r | |
827 | *\r | |
828 | * @param {Ext.form.Panel} options.failure.form\r | |
829 | * The {@link Ext.form.Panel} that requested the load.\r | |
830 | *\r | |
831 | * @param {Ext.form.Panel} options.failure.result\r | |
832 | * The failed response or result object returned by the server which performed the operation.\r | |
833 | *\r | |
834 | * @param {Object} options.success.data\r | |
835 | * The parsed data returned by the server.\r | |
836 | *\r | |
837 | * @param {Object} options.scope\r | |
838 | * The scope in which to call the callback functions (The `this` reference for the callback functions).\r | |
839 | *\r | |
840 | * @return {Ext.data.Connection} The request object.\r | |
841 | */\r | |
842 | load : function(options) {\r | |
843 | options = options || {};\r | |
844 | \r | |
845 | var me = this,\r | |
846 | api = me.getApi(),\r | |
847 | url = me.getUrl() || options.url,\r | |
848 | waitMsg = options.waitMsg,\r | |
849 | successFn = function(response, data) {\r | |
850 | me.setValues(data.data);\r | |
851 | \r | |
852 | if (Ext.isFunction(options.success)) {\r | |
853 | options.success.call(options.scope || me, me, response, data);\r | |
854 | }\r | |
855 | \r | |
856 | me.fireEvent('load', me, response);\r | |
857 | },\r | |
858 | failureFn = function(response, data) {\r | |
859 | if (Ext.isFunction(options.failure)) {\r | |
860 | options.failure.call(scope, me, response, data);\r | |
861 | }\r | |
862 | \r | |
863 | me.fireEvent('exception', me, response);\r | |
864 | },\r | |
865 | load, method, args;\r | |
866 | \r | |
867 | if (options.waitMsg) {\r | |
868 | if (typeof waitMsg === 'string') {\r | |
869 | waitMsg = {\r | |
870 | xtype : 'loadmask',\r | |
871 | message : waitMsg\r | |
872 | };\r | |
873 | }\r | |
874 | \r | |
875 | me.setMasked(waitMsg);\r | |
876 | }\r | |
877 | \r | |
878 | if (api) {\r | |
879 | load = api.load;\r | |
880 | \r | |
881 | if (typeof load === 'string') {\r | |
882 | load = Ext.direct.Manager.parseMethod(load);\r | |
883 | \r | |
884 | if (load) {\r | |
885 | api.load = load;\r | |
886 | }\r | |
887 | }\r | |
888 | \r | |
889 | if (load) {\r | |
890 | method = load.directCfg.method;\r | |
891 | args = method.getArgs(me.getParams(options.params), me.getParamOrder(), me.getParamsAsHash());\r | |
892 | \r | |
893 | args.push(function(data, response, success) {\r | |
894 | me.setMasked(false);\r | |
895 | \r | |
896 | if (success) {\r | |
897 | successFn(response, data);\r | |
898 | } else {\r | |
899 | failureFn(response, data);\r | |
900 | }\r | |
901 | }, me);\r | |
902 | \r | |
903 | return load.apply(window, args);\r | |
904 | }\r | |
905 | } else if (url) {\r | |
906 | return Ext.Ajax.request({\r | |
907 | url: url,\r | |
908 | timeout: (options.timeout || this.getTimeout()) * 1000,\r | |
909 | method: options.method || 'GET',\r | |
910 | autoAbort: options.autoAbort,\r | |
911 | headers: Ext.apply(\r | |
912 | {\r | |
913 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'\r | |
914 | },\r | |
915 | options.headers || {}\r | |
916 | ),\r | |
917 | callback: function(callbackOptions, success, response) {\r | |
918 | var responseText = response.responseText,\r | |
919 | statusResult = Ext.data.request.Ajax.parseStatus(response.status, response);\r | |
920 | \r | |
921 | me.setMasked(false);\r | |
922 | \r | |
923 | if (success) {\r | |
924 | if (statusResult && responseText.length === 0) {\r | |
925 | success = true;\r | |
926 | } else {\r | |
927 | response = Ext.decode(responseText);\r | |
928 | success = !!response.success;\r | |
929 | }\r | |
930 | if (success) {\r | |
931 | successFn(response, responseText);\r | |
932 | } else {\r | |
933 | failureFn(response, responseText);\r | |
934 | }\r | |
935 | }\r | |
936 | else {\r | |
937 | failureFn(response, responseText);\r | |
938 | }\r | |
939 | }\r | |
940 | });\r | |
941 | }\r | |
942 | },\r | |
943 | \r | |
944 | /**\r | |
945 | * @private\r | |
946 | */\r | |
947 | getParams : function(params) {\r | |
948 | return Ext.apply({}, params, this.getBaseParams());\r | |
949 | },\r | |
950 | \r | |
951 | /**\r | |
952 | * Sets the values of form fields in bulk. Example usage:\r | |
953 | *\r | |
954 | * myForm.setValues({\r | |
955 | * name: 'Ed',\r | |
956 | * crazy: true,\r | |
957 | * username: 'edspencer'\r | |
958 | * });\r | |
959 | *\r | |
960 | * If there groups of checkbox fields with the same name, pass their values in an array. For example:\r | |
961 | *\r | |
962 | * myForm.setValues({\r | |
963 | * name: 'Jacky',\r | |
964 | * crazy: false,\r | |
965 | * hobbies: [\r | |
966 | * 'reading',\r | |
967 | * 'cooking',\r | |
968 | * 'gaming'\r | |
969 | * ]\r | |
970 | * });\r | |
971 | *\r | |
972 | * @param {Object} values field name => value mapping object.\r | |
973 | * @return {Ext.form.Panel} This form.\r | |
974 | */\r | |
975 | setValues: function(values) {\r | |
976 | var fields = this.getFields(),\r | |
977 | me = this,\r | |
978 | name, field, value, ln, i, f;\r | |
979 | \r | |
980 | values = values || {};\r | |
981 | \r | |
982 | for (name in values) {\r | |
983 | if (values.hasOwnProperty(name)) {\r | |
984 | field = fields[name];\r | |
985 | value = values[name];\r | |
986 | \r | |
987 | if (field) {\r | |
988 | // If there are multiple fields with the same name. Checkboxes, radio fields and maybe event just normal fields..\r | |
989 | if (Ext.isArray(field)) {\r | |
990 | ln = field.length;\r | |
991 | \r | |
992 | // Loop through each of the fields\r | |
993 | for (i = 0; i < ln; i++) {\r | |
994 | f = field[i];\r | |
995 | \r | |
996 | if (f.isRadio) {\r | |
997 | // If it is a radio field just use setGroupValue which will handle all of the radio fields\r | |
998 | f.setGroupValue(value);\r | |
999 | break;\r | |
1000 | } else if (f.isCheckbox) {\r | |
1001 | if (Ext.isArray(value)) {\r | |
1002 | f.setChecked((value.indexOf(f._value) != -1));\r | |
1003 | } else {\r | |
1004 | f.setChecked((value == f._value));\r | |
1005 | }\r | |
1006 | } else {\r | |
1007 | // If it is a bunch of fields with the same name, check if the value is also an array, so we can map it\r | |
1008 | // to each field\r | |
1009 | if (Ext.isArray(value)) {\r | |
1010 | f.setValue(value[i]);\r | |
1011 | }\r | |
1012 | }\r | |
1013 | }\r | |
1014 | } else {\r | |
1015 | if (field.isRadio || field.isCheckbox) {\r | |
1016 | // If the field is a radio or a checkbox\r | |
1017 | field.setChecked(value);\r | |
1018 | } else {\r | |
1019 | // If just a normal field\r | |
1020 | field.setValue(value);\r | |
1021 | }\r | |
1022 | }\r | |
1023 | \r | |
1024 | if (me.getTrackResetOnLoad()) {\r | |
1025 | field.resetOriginalValue();\r | |
1026 | }\r | |
1027 | }\r | |
1028 | }\r | |
1029 | }\r | |
1030 | \r | |
1031 | return this;\r | |
1032 | },\r | |
1033 | \r | |
1034 | /**\r | |
1035 | * Returns an object containing the value of each field in the form, keyed to the field's name.\r | |
1036 | * For groups of checkbox fields with the same name, it will be arrays of values. For example:\r | |
1037 | *\r | |
1038 | * {\r | |
1039 | * name: "Jacky Nguyen", // From a TextField\r | |
1040 | * favorites: [\r | |
1041 | * 'pizza',\r | |
1042 | * 'noodle',\r | |
1043 | * 'cake'\r | |
1044 | * ]\r | |
1045 | * }\r | |
1046 | *\r | |
1047 | * @param {Boolean} [enabled] `true` to return only enabled fields.\r | |
1048 | * @param {Boolean} [all] `true` to return all fields even if they don't have a\r | |
1049 | * {@link Ext.field.Field#name name} configured.\r | |
1050 | * @return {Object} Object mapping field name to its value.\r | |
1051 | */\r | |
1052 | getValues: function(enabled, all) {\r | |
1053 | var fields = this.getFields(),\r | |
1054 | values = {},\r | |
1055 | isArray = Ext.isArray,\r | |
1056 | field, value, addValue, bucket, name, ln, i;\r | |
1057 | \r | |
1058 | // Function which you give a field and a name, and it will add it into the values\r | |
1059 | // object accordingly\r | |
1060 | addValue = function(field, name) {\r | |
1061 | if (!all && (!name || name === 'null') || field.isFile) {\r | |
1062 | return;\r | |
1063 | }\r | |
1064 | \r | |
1065 | if (field.isCheckbox) {\r | |
1066 | value = field.getSubmitValue();\r | |
1067 | } else {\r | |
1068 | value = field.getValue();\r | |
1069 | }\r | |
1070 | \r | |
1071 | \r | |
1072 | if (!(enabled && field.getDisabled())) {\r | |
1073 | // RadioField is a special case where the value returned is the fields valUE\r | |
1074 | // ONLY if it is checked\r | |
1075 | if (field.isRadio) {\r | |
1076 | if (field.isChecked()) {\r | |
1077 | values[name] = value;\r | |
1078 | }\r | |
1079 | } else {\r | |
1080 | // Check if the value already exists\r | |
1081 | bucket = values[name];\r | |
1082 | if (!Ext.isEmpty(bucket)) {\r | |
1083 | // if it does and it isn't an array, we need to make it into an array\r | |
1084 | // so we can push more\r | |
1085 | if (!isArray(bucket)) {\r | |
1086 | bucket = values[name] = [bucket];\r | |
1087 | }\r | |
1088 | \r | |
1089 | // Check if it is an array\r | |
1090 | if (isArray(value)) {\r | |
1091 | // Concat it into the other values\r | |
1092 | bucket = values[name] = bucket.concat(value);\r | |
1093 | } else {\r | |
1094 | // If it isn't an array, just pushed more values\r | |
1095 | bucket.push(value);\r | |
1096 | }\r | |
1097 | } else {\r | |
1098 | values[name] = value;\r | |
1099 | }\r | |
1100 | }\r | |
1101 | }\r | |
1102 | };\r | |
1103 | \r | |
1104 | // Loop through each of the fields, and add the values for those fields.\r | |
1105 | for (name in fields) {\r | |
1106 | if (fields.hasOwnProperty(name)) {\r | |
1107 | field = fields[name];\r | |
1108 | \r | |
1109 | if (isArray(field)) {\r | |
1110 | ln = field.length;\r | |
1111 | for (i = 0; i < ln; i++) {\r | |
1112 | addValue(field[i], name);\r | |
1113 | }\r | |
1114 | } else {\r | |
1115 | addValue(field, name);\r | |
1116 | }\r | |
1117 | }\r | |
1118 | }\r | |
1119 | \r | |
1120 | return values;\r | |
1121 | },\r | |
1122 | \r | |
1123 | /**\r | |
1124 | * Resets all fields in the form back to their original values.\r | |
1125 | * @return {Ext.form.Panel} This form.\r | |
1126 | */\r | |
1127 | reset: function() {\r | |
1128 | this.getFieldsAsArray().forEach(function(field) {\r | |
1129 | field.reset();\r | |
1130 | });\r | |
1131 | \r | |
1132 | return this;\r | |
1133 | },\r | |
1134 | \r | |
1135 | /**\r | |
1136 | * A convenient method to disable all fields in this form.\r | |
1137 | * @return {Ext.form.Panel} This form.\r | |
1138 | */\r | |
1139 | updateDisabled: function(newDisabled) {\r | |
1140 | this.getFieldsAsArray().forEach(function(field) {\r | |
1141 | field.setDisabled(newDisabled);\r | |
1142 | });\r | |
1143 | \r | |
1144 | return this;\r | |
1145 | },\r | |
1146 | \r | |
1147 | /**\r | |
1148 | * @private\r | |
1149 | */\r | |
1150 | getFieldsAsArray: function() {\r | |
1151 | var fields = [],\r | |
1152 | getFieldsFrom = function(item) {\r | |
1153 | if (item.isField) {\r | |
1154 | fields.push(item);\r | |
1155 | }\r | |
1156 | \r | |
1157 | if (item.isContainer) {\r | |
1158 | item.getItems().each(getFieldsFrom);\r | |
1159 | }\r | |
1160 | };\r | |
1161 | \r | |
1162 | this.getItems().each(getFieldsFrom);\r | |
1163 | \r | |
1164 | return fields;\r | |
1165 | },\r | |
1166 | \r | |
1167 | /**\r | |
1168 | * Returns all {@link Ext.field.Field field} instances inside this form.\r | |
1169 | * @param {Boolean} byName return only fields that match the given name, otherwise return all fields.\r | |
1170 | * @return {Object/Array} All field instances, mapped by field name; or an array if `byName` is passed.\r | |
1171 | */\r | |
1172 | getFields: function(byName) {\r | |
1173 | var fields = {},\r | |
1174 | itemName;\r | |
1175 | \r | |
1176 | var getFieldsFrom = function(item) {\r | |
1177 | if (item.isField) {\r | |
1178 | itemName = item.getName();\r | |
1179 | \r | |
1180 | if ((byName && itemName == byName) || typeof byName == 'undefined') {\r | |
1181 | if (fields.hasOwnProperty(itemName)) {\r | |
1182 | if (!Ext.isArray(fields[itemName])) {\r | |
1183 | fields[itemName] = [fields[itemName]];\r | |
1184 | }\r | |
1185 | \r | |
1186 | fields[itemName].push(item);\r | |
1187 | } else {\r | |
1188 | fields[itemName] = item;\r | |
1189 | }\r | |
1190 | }\r | |
1191 | \r | |
1192 | }\r | |
1193 | \r | |
1194 | if (item.isContainer) {\r | |
1195 | item.items.each(getFieldsFrom);\r | |
1196 | }\r | |
1197 | };\r | |
1198 | \r | |
1199 | this.getItems().each(getFieldsFrom);\r | |
1200 | \r | |
1201 | return (byName) ? (fields[byName] || []) : fields;\r | |
1202 | },\r | |
1203 | \r | |
1204 | /**\r | |
1205 | * Returns an array of fields in this formpanel.\r | |
1206 | * @return {Ext.field.Field[]} An array of fields in this form panel.\r | |
1207 | * @private\r | |
1208 | */\r | |
1209 | getFieldsArray: function() {\r | |
1210 | var fields = [];\r | |
1211 | \r | |
1212 | var getFieldsFrom = function(item) {\r | |
1213 | if (item.isField) {\r | |
1214 | fields.push(item);\r | |
1215 | }\r | |
1216 | \r | |
1217 | if (item.isContainer) {\r | |
1218 | item.items.each(getFieldsFrom);\r | |
1219 | }\r | |
1220 | };\r | |
1221 | \r | |
1222 | this.items.each(getFieldsFrom);\r | |
1223 | \r | |
1224 | return fields;\r | |
1225 | },\r | |
1226 | \r | |
1227 | getFieldsFromItem: Ext.emptyFn,\r | |
1228 | \r | |
1229 | /**\r | |
1230 | * Shows a generic/custom mask over a designated Element.\r | |
1231 | * @param {String/Object} cfg Either a string message or a configuration object supporting\r | |
1232 | * the following options:\r | |
1233 | *\r | |
1234 | * {\r | |
1235 | * message : 'Please Wait',\r | |
1236 | * cls : 'form-mask'\r | |
1237 | * }\r | |
1238 | *\r | |
1239 | * @param {Object} target\r | |
1240 | * @return {Ext.form.Panel} This form\r | |
1241 | * @deprecated 2.0.0 Please use {@link #setMasked} instead.\r | |
1242 | */\r | |
1243 | showMask: function(cfg, target) {\r | |
1244 | //<debug>\r | |
1245 | Ext.Logger.warn('showMask is now deprecated. Please use Ext.form.Panel#setMasked instead');\r | |
1246 | //</debug>\r | |
1247 | \r | |
1248 | cfg = Ext.isObject(cfg) ? cfg.message : cfg;\r | |
1249 | \r | |
1250 | if (cfg) {\r | |
1251 | this.setMasked({\r | |
1252 | xtype: 'loadmask',\r | |
1253 | message: cfg\r | |
1254 | });\r | |
1255 | } else {\r | |
1256 | this.setMasked(true);\r | |
1257 | }\r | |
1258 | \r | |
1259 | return this;\r | |
1260 | },\r | |
1261 | \r | |
1262 | /**\r | |
1263 | * Hides a previously shown wait mask (See {@link #showMask}).\r | |
1264 | * @return {Ext.form.Panel} this\r | |
1265 | * @deprecated 2.0.0 Please use {@link #unmask} or {@link #setMasked} instead.\r | |
1266 | */\r | |
1267 | hideMask: function() {\r | |
1268 | this.setMasked(false);\r | |
1269 | return this;\r | |
1270 | },\r | |
1271 | \r | |
1272 | /**\r | |
1273 | * Returns the currently focused field\r | |
1274 | * @return {Ext.field.Field} The currently focused field, if one is focused or `null`.\r | |
1275 | * @private\r | |
1276 | */\r | |
1277 | getFocusedField: function() {\r | |
1278 | var fields = this.getFieldsArray(),\r | |
1279 | ln = fields.length,\r | |
1280 | field, i;\r | |
1281 | \r | |
1282 | for (i = 0; i < ln; i++) {\r | |
1283 | field = fields[i];\r | |
1284 | if (field.isFocused) {\r | |
1285 | return field;\r | |
1286 | }\r | |
1287 | }\r | |
1288 | \r | |
1289 | return null;\r | |
1290 | },\r | |
1291 | \r | |
1292 | /**\r | |
1293 | * @return {Boolean/Ext.field.Field} The next field if one exists, or `false`.\r | |
1294 | * @private\r | |
1295 | */\r | |
1296 | getNextField: function() {\r | |
1297 | var fields = this.getFieldsArray(),\r | |
1298 | focusedField = this.getFocusedField(),\r | |
1299 | index;\r | |
1300 | \r | |
1301 | if (focusedField) {\r | |
1302 | index = fields.indexOf(focusedField);\r | |
1303 | \r | |
1304 | if (index !== fields.length - 1) {\r | |
1305 | index++;\r | |
1306 | return fields[index];\r | |
1307 | }\r | |
1308 | }\r | |
1309 | \r | |
1310 | return false;\r | |
1311 | },\r | |
1312 | \r | |
1313 | /**\r | |
1314 | * Tries to focus the next field in the form, if there is currently a focused field.\r | |
1315 | * @return {Boolean/Ext.field.Field} The next field that was focused, or `false`.\r | |
1316 | * @private\r | |
1317 | */\r | |
1318 | focusNextField: function() {\r | |
1319 | var field = this.getNextField();\r | |
1320 | if (field) {\r | |
1321 | field.focus();\r | |
1322 | return field;\r | |
1323 | }\r | |
1324 | \r | |
1325 | return false;\r | |
1326 | },\r | |
1327 | \r | |
1328 | /**\r | |
1329 | * @private\r | |
1330 | * @return {Boolean/Ext.field.Field} The next field if one exists, or `false`.\r | |
1331 | */\r | |
1332 | getPreviousField: function() {\r | |
1333 | var fields = this.getFieldsArray(),\r | |
1334 | focusedField = this.getFocusedField(),\r | |
1335 | index;\r | |
1336 | \r | |
1337 | if (focusedField) {\r | |
1338 | index = fields.indexOf(focusedField);\r | |
1339 | \r | |
1340 | if (index !== 0) {\r | |
1341 | index--;\r | |
1342 | return fields[index];\r | |
1343 | }\r | |
1344 | }\r | |
1345 | \r | |
1346 | return false;\r | |
1347 | },\r | |
1348 | \r | |
1349 | /**\r | |
1350 | * Tries to focus the previous field in the form, if there is currently a focused field.\r | |
1351 | * @return {Boolean/Ext.field.Field} The previous field that was focused, or `false`.\r | |
1352 | * @private\r | |
1353 | */\r | |
1354 | focusPreviousField: function() {\r | |
1355 | var field = this.getPreviousField();\r | |
1356 | if (field) {\r | |
1357 | field.focus();\r | |
1358 | return field;\r | |
1359 | }\r | |
1360 | \r | |
1361 | return false;\r | |
1362 | }\r | |
1363 | });\r |