erp_forms 2.0.6 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. data/app/controllers/erp_forms/erp_app/desktop/dynamic_forms/base_controller.rb +4 -37
  2. data/app/controllers/erp_forms/erp_app/desktop/dynamic_forms/data_controller.rb +348 -82
  3. data/app/controllers/erp_forms/erp_app/desktop/dynamic_forms/forms_controller.rb +110 -15
  4. data/app/controllers/erp_forms/erp_app/desktop/dynamic_forms/models_controller.rb +19 -3
  5. data/app/mailers/dynamic_form_mailer.rb +35 -0
  6. data/app/models/dynamic_datum.rb +97 -22
  7. data/app/models/dynamic_form.rb +172 -98
  8. data/app/models/dynamic_form_document.rb +4 -11
  9. data/app/models/dynamic_form_model.rb +46 -22
  10. data/app/models/ticket.rb +4 -0
  11. data/app/views/dynamic_form_mailer/widget_email_with_attachments.html.erb +3 -0
  12. data/app/views/dynamic_form_mailer/widget_email_with_attachments.text.erb +3 -0
  13. data/app/widgets/dynamic_forms/base.rb +101 -19
  14. data/app/widgets/dynamic_forms/javascript/dynamic_forms.js +40 -38
  15. data/app/widgets/dynamic_forms/views/error.html.erb +1 -0
  16. data/db/data_migrations/20110608185830_create_default_dynamic_models_and_forms.rb +2 -0
  17. data/db/data_migrations/20120824013449_create_ticket_form.rb +1 -0
  18. data/db/data_migrations/20121026013449_update_ticket_form.rb +64 -0
  19. data/db/data_migrations/{20120904191738_update_contact_form.rb → 20121026191738_update_contact_form.rb} +4 -0
  20. data/db/migrate/20110530193446_dynamic_forms.rb +12 -0
  21. data/db/migrate/20121007022323_upgrade_dynamic_forms_table.rb +31 -0
  22. data/lib/erp_forms.rb +4 -0
  23. data/lib/erp_forms/dynamic_form_field.rb +31 -28
  24. data/lib/erp_forms/dynamic_grid_column.rb +2 -2
  25. data/lib/erp_forms/engine.rb +5 -0
  26. data/lib/erp_forms/extensions/active_record/acts_as_commentable.rb +33 -0
  27. data/lib/erp_forms/extensions/active_record/acts_as_dynamic_form_model.rb +80 -0
  28. data/lib/erp_forms/extensions/active_record/has_dynamic_forms.rb +4 -4
  29. data/lib/erp_forms/extensions/extensions.rb +2 -0
  30. data/lib/erp_forms/extensions/railties/action_view.rb +2 -2
  31. data/lib/erp_forms/version.rb +2 -2
  32. data/public/javascripts/erp_app/desktop/applications/dynamic_forms/center_region.js +2 -1
  33. data/public/javascripts/erp_app/desktop/applications/dynamic_forms/dynamic_data_grid.js +264 -82
  34. data/public/javascripts/erp_app/desktop/applications/dynamic_forms/form_builder.js +1476 -58
  35. data/public/javascripts/erp_app/desktop/applications/dynamic_forms/module.js +24 -1
  36. data/public/javascripts/erp_app/desktop/applications/dynamic_forms/west_region.js +493 -210
  37. data/public/javascripts/erp_app/shared/dynamic_forms/dynamic_form_fields.js +82 -20
  38. data/public/javascripts/erp_app/shared/dynamic_forms/dynamic_forms_validation.js +23 -3
  39. data/spec/dummy/config/application.rb +6 -2
  40. data/spec/dummy/config/environments/spec.rb +3 -0
  41. data/spec/dummy/db/data_migrations/20110109173616_create_capability_scope_types.erp_tech_svcs.rb +15 -0
  42. data/spec/dummy/db/data_migrations/20110525001935_add_usd_currency.erp_base_erp_svcs.rb +12 -0
  43. data/spec/dummy/db/data_migrations/20110608185830_create_default_dynamic_models_and_forms.erp_forms.rb +33 -0
  44. data/spec/dummy/db/data_migrations/20110609150135_add_iso_codes.erp_base_erp_svcs.rb +19 -0
  45. data/spec/dummy/db/data_migrations/20110728201729_erp_app_setup.erp_app.rb +252 -0
  46. data/spec/dummy/db/data_migrations/20110728201733_update_preferences.erp_app.rb +53 -0
  47. data/spec/dummy/db/data_migrations/20110802200222_schedule_delete_expired_sessions_job.erp_tech_svcs.rb +16 -0
  48. data/spec/dummy/db/data_migrations/20110816161238_create_desktop_app_audit_log_viewer.erp_app.rb +21 -0
  49. data/spec/dummy/db/data_migrations/20110817160743_add_file_manager_application.erp_app.rb +32 -0
  50. data/spec/dummy/db/data_migrations/20110828190913_create_desktop_app_dynamic_forms.erp_forms.rb +19 -0
  51. data/spec/dummy/db/data_migrations/20110913145838_setup_compass_ae_instance.erp_base_erp_svcs.rb +12 -0
  52. data/spec/dummy/db/data_migrations/20111108183739_add_default_capabilities.erp_app.rb +23 -0
  53. data/spec/dummy/db/data_migrations/20111108183740_add_new_contact_widgets.erp_app.rb +42 -0
  54. data/spec/dummy/db/data_migrations/20111111144706_setup_audit_log_types.erp_tech_svcs.rb +22 -0
  55. data/spec/dummy/db/data_migrations/20120109173616_create_download_capability_type.erp_tech_svcs.rb +14 -0
  56. data/spec/dummy/db/data_migrations/20120229160222_add_userinfo_widget.erp_app.rb +29 -0
  57. data/spec/dummy/db/data_migrations/20120405193721_create_party_and_role_type_for_communication_events.erp_app.rb +11 -0
  58. data/spec/dummy/db/data_migrations/20120411180756_create_user_management_mobile_application.erp_app.rb +19 -0
  59. data/spec/dummy/db/data_migrations/20120418164215_create_configuration_management_desktop_application.erp_app.rb +23 -0
  60. data/spec/dummy/db/data_migrations/20120824013449_create_ticket_form.erp_forms.rb +67 -0
  61. data/spec/dummy/db/data_migrations/20121026013449_update_ticket_form.erp_forms.rb +65 -0
  62. data/spec/dummy/db/data_migrations/20121026191738_update_contact_form.erp_forms.rb +27 -0
  63. data/spec/dummy/db/data_migrations/20121116155018_create_group_relationship_and_role_types.erp_tech_svcs.rb +20 -0
  64. data/spec/dummy/db/data_migrations/20121130201859_upgrade_remove_system_mgmt_app.erp_app.rb +16 -0
  65. data/spec/dummy/db/data_migrations/20121130212146_note_capabilities.erp_tech_svcs.rb +24 -0
  66. data/spec/dummy/db/data_migrations/20121218175028_create_security_management_desktop_application.erp_app.rb +23 -0
  67. data/spec/dummy/db/migrate/20121213234847_base_erp_services.erp_base_erp_svcs.rb +461 -0
  68. data/spec/dummy/db/migrate/20121213234848_base_tech_services.erp_tech_svcs.rb +255 -0
  69. data/spec/dummy/db/migrate/20121213234849_create_has_attribute_tables.erp_tech_svcs.rb +39 -0
  70. data/spec/dummy/db/migrate/20121213234850_base_app_framework.erp_app.rb +276 -0
  71. data/spec/dummy/db/migrate/20121213234851_dynamic_forms.erp_forms.rb +95 -0
  72. data/spec/dummy/db/migrate/20121213234852_create_tickets.erp_forms.rb +19 -0
  73. data/spec/dummy/db/migrate/20121213234853_upgrade_dynamic_forms_table.erp_forms.rb +32 -0
  74. data/spec/dummy/db/migrate/20130107181041_create_groups.erp_tech_svcs.rb +19 -0
  75. data/spec/dummy/db/migrate/20130107181042_upgrade_security.erp_tech_svcs.rb +54 -0
  76. data/spec/dummy/db/migrate/20130107181043_upgrade_security2.erp_tech_svcs.rb +270 -0
  77. data/spec/dummy/db/schema.rb +879 -0
  78. data/spec/dummy/db/spec.sqlite3 +0 -0
  79. data/spec/dummy/log/spec.log +13580 -0
  80. data/spec/models/dynamic_form_model_spec.rb +1 -1
  81. data/spec/spec_helper.rb +11 -3
  82. metadata +136 -14
@@ -1,6 +1,169 @@
1
+ Ext.define('DynamicForm', {
2
+ extend: 'Ext.data.Model',
3
+ fields: [
4
+ {name: 'id', type: 'number'},
5
+ {name: 'description', type: 'string'},
6
+ {name: 'model_name', type: 'string'},
7
+ {name: 'definition', type: 'string'},
8
+ {name: 'internal_identifier', type: 'string'},
9
+ {name: 'widget_action', type: 'string'},
10
+ {name: 'widget_email_recipients', type: 'string'},
11
+ {name: 'focus_first_field', type: 'boolean'},
12
+ {name: 'submit_empty_text', type: 'boolean'},
13
+ {name: 'msg_target', type: 'string'},
14
+ {name: 'submit_button_label', type: 'string'},
15
+ {name: 'cancel_button_label', type: 'string'},
16
+ {name: 'comment', type: 'string'},
17
+ {name: 'created_at', type: 'string'},
18
+ {name: 'updated_at', type: 'string'},
19
+ {name: 'created_by', type: 'string'},
20
+ {name: 'updated_by', type: 'string'}
21
+ ]
22
+ });
23
+
24
+ // get a single form and fire openFormTab
25
+ Ext.create('Ext.data.Store', {
26
+ model: 'DynamicForm',
27
+ storeId: 'dynamicFormStore',
28
+ timeout : 90000,
29
+ proxy: {
30
+ type: 'ajax',
31
+ url: '/erp_forms/erp_app/desktop/dynamic_forms/forms/get_record',
32
+ method: 'POST'
33
+ },
34
+ listeners:{
35
+ 'load':function(store, records){
36
+ var record = store.getAt(0);
37
+ Ext.getCmp('dynamic_forms_westregion').openFormTab(record);
38
+ }
39
+ },
40
+ autoLoad: false
41
+ });
42
+
43
+ Ext.define('FieldType', {
44
+ extend: 'Ext.data.Model',
45
+ fields: [
46
+ {name: 'text', type: 'string'},
47
+ {name: 'field_xtype', type: 'string'},
48
+ {name: 'fieldLabel', type: 'string'},
49
+ {name: 'leaf', type: 'boolean'}
50
+ ]
51
+ });
52
+
53
+ var fieldStore = Ext.create('Ext.data.TreeStore', {
54
+ autoLoad:false,
55
+ model: 'FieldType',
56
+ proxy: {
57
+ type: 'memory'
58
+ },
59
+ folderSort: true
60
+ });
61
+
62
+ var fieldData = {
63
+ text:"Field Types",
64
+ expanded: true,
65
+ expandable: false,
66
+ children: [
67
+ {
68
+ text: 'Checkbox',
69
+ field_xtype: 'checkbox',
70
+ leaf: true
71
+ },
72
+ {
73
+ text: 'Combo Box',
74
+ field_xtype: 'combobox',
75
+ leaf: true
76
+ },
77
+ {
78
+ text: 'Date Field',
79
+ field_xtype: 'datefield',
80
+ leaf: true
81
+ },
82
+ {
83
+ text: 'Display Field',
84
+ field_xtype: 'displayfield',
85
+ leaf: true
86
+ },
87
+ {
88
+ text: 'Email Field',
89
+ field_xtype: 'email',
90
+ leaf: true
91
+ },
92
+ {
93
+ text: 'File Upload',
94
+ field_xtype: 'filefield',
95
+ leaf: true,
96
+ vtype: 'file'
97
+ },
98
+ {
99
+ text: 'Hidden Field',
100
+ field_xtype: 'hiddenfield',
101
+ leaf: true
102
+ },
103
+ {
104
+ text: 'Number Field',
105
+ field_xtype: 'numberfield',
106
+ leaf: true
107
+ },
108
+ {
109
+ text: 'Password Field',
110
+ field_xtype: 'password',
111
+ leaf: true
112
+ },
113
+ {
114
+ text: 'Related Combo Box',
115
+ field_xtype: 'related_combobox',
116
+ leaf: true,
117
+ qtip: 'Combo Box with dynamic store. Use with small data sets. Use limited to secure pages.'
118
+ },
119
+ {
120
+ text: 'Related Search Box',
121
+ field_xtype: 'related_searchbox',
122
+ leaf: true,
123
+ qtip: 'Combo Box with dynamic store. Use with large data sets. Use limited to secure pages.'
124
+ },
125
+ {
126
+ text: 'Text Field',
127
+ field_xtype: 'textfield',
128
+ leaf: true
129
+ },
130
+ {
131
+ text: 'Text Area',
132
+ field_xtype: 'textarea',
133
+ leaf: true
134
+ },
135
+ {
136
+ text: 'Time Field',
137
+ field_xtype: 'timefield',
138
+ leaf: true
139
+ },
140
+ {
141
+ text: 'Yes / No',
142
+ field_xtype: 'yesno',
143
+ leaf: true
144
+ }
145
+ ]};
146
+
147
+ var fieldTreeRootNode = fieldStore.setRootNode(fieldData);
148
+
1
149
  Ext.define("Compass.ErpApp.Desktop.Applications.DynamicForms.FormBuilder",{
2
- extend:"Ext.window.Window",
150
+ extend:"Ext.panel.Panel",
3
151
  alias:'widget.dynamic_forms_FormBuilder',
152
+
153
+ height: 458,
154
+ width: 811,
155
+ layout: {
156
+ type: 'border'
157
+ },
158
+
159
+ setWindowStatus : function(status){
160
+ this.findParentByType('statuswindow').setStatus(status);
161
+ },
162
+
163
+ clearWindowStatus : function(){
164
+ this.findParentByType('statuswindow').clearStatus();
165
+ },
166
+
4
167
  initComponent : function() {
5
168
 
6
169
  this.addEvents(
@@ -23,71 +186,1326 @@ Ext.define("Compass.ErpApp.Desktop.Applications.DynamicForms.FormBuilder",{
23
186
  this.callParent(arguments);
24
187
  },
25
188
 
26
- constructor : function(config) {
27
- config = Ext.apply({
28
- layout:'fit',
29
- title:'Form Builder',
30
- autoHeight:true,
31
- iconCls:'icon-document',
32
- width:400,
33
- height:300,
34
- buttonAlign:'center',
35
- plain: true,
36
- items: new Ext.form.FormPanel({
37
- timeout: 130000,
38
- // baseParams:config['baseParams'],
39
- autoHeight:true,
40
- labelWidth:110,
41
- frame:false,
42
- layout:'fit',
43
- // url:config['url'],
44
- defaults: {
45
- width: 225
46
- },
47
- items: [{
48
- xtype: 'textarea',
49
- hideLabel:true,
50
- name:'comment'
51
- }]
52
- }),
53
- buttons: [{
54
- text:'Submit',
189
+ getFieldOptionsForField : function(field){
190
+ var xtype = field.xtype;
191
+ var field_xtype = field.field_xtype; // used to determine if it is a hidden field
192
+
193
+ var updateFieldType = {
194
+ fieldLabel: 'Type',
195
+ name: 'updateFieldType',
196
+ xtype: 'displayfield',
197
+ allowBlank: false
198
+ };
199
+
200
+ var updateName = {
201
+ fieldLabel: 'Name',
202
+ name: 'updateName',
203
+ xtype: 'textfield',
204
+ allowBlank: false
205
+ };
206
+
207
+ if (xtype == 'filefield') updateName.readOnly = true;
208
+
209
+ //console.log(xtype);
210
+ var base_top = [
211
+ updateFieldType,
212
+ updateName,
213
+ {
214
+ fieldLabel: 'Label',
215
+ name: 'updateLabel',
216
+ xtype: 'textfield',
217
+ allowBlank: false
218
+ }
219
+ ];
220
+
221
+ var common = [
222
+ {
223
+ fieldLabel: 'Label Alignment',
224
+ name: 'updateLabelAlign',
225
+ xtype: 'combobox',
226
+ allowBlank: false,
227
+ editable: true,
228
+ forceSelection:true,
229
+ value: 'left',
230
+ store: [
231
+ ['left', 'Left of Field'],
232
+ ['top', 'Above Field']
233
+ ]
234
+ },
235
+ {
236
+ fieldLabel: 'Label Width',
237
+ name: 'updateLabelWidth',
238
+ xtype: 'numberfield'
239
+ },
240
+ {
241
+ fieldLabel: 'Width',
242
+ name: 'updateWidth',
243
+ xtype: 'numberfield'
244
+ },
245
+ {
246
+ fieldLabel: 'Height',
247
+ name: 'updateHeight',
248
+ xtype: 'numberfield'
249
+ },
250
+ {
251
+ fieldLabel: 'Empty Text',
252
+ name: 'updateEmptyText',
253
+ xtype: 'textfield'
254
+ },
255
+ {
256
+ fieldLabel: 'Help Text',
257
+ name: 'updateHelpQtip',
258
+ xtype: 'textfield',
259
+ plugins: [new helpQtip("Add help text via a mouseover icon to the right of the field.")]
260
+ },
261
+ {
262
+ fieldLabel: 'Allow Blank',
263
+ name: 'updateAllowBlank',
264
+ xtype: 'checkbox'
265
+ }
266
+ ];
267
+
268
+ var base_bottom = [
269
+ {
270
+ fieldLabel: 'Default Value',
271
+ name: 'updateValue',
272
+ xtype: 'textfield'
273
+ },
274
+ {
275
+ fieldLabel: 'Read Only',
276
+ name: 'updateReadOnly',
277
+ xtype: 'checkbox'
278
+ },
279
+ {
280
+ fieldLabel: 'Display In Grid',
281
+ name: 'updateDisplayInGrid',
282
+ xtype: 'checkbox'
283
+ },
284
+ {
285
+ fieldLabel: 'Searchable',
286
+ name: 'updateSearchable',
287
+ xtype: 'checkbox',
288
+ plugins: [new helpQtip("Make this field searchable. Requires Solr via Compass AE's erp_search engine.")]
289
+ }
290
+ ];
291
+
292
+ var filefield = [
293
+ {
294
+ fieldLabel: 'Button Text',
295
+ name: 'updateButtonText',
296
+ xtype: 'textfield'
297
+ }
298
+ ];
299
+
300
+ var common_combobox = [
301
+ {
302
+ fieldLabel: 'Editable',
303
+ name: 'updateEditable',
304
+ xtype: 'checkbox'
305
+ },
306
+ {
307
+ fieldLabel: 'Force Selection',
308
+ name: 'updateForceSelection',
309
+ xtype: 'checkbox'
310
+ },
311
+ {
312
+ fieldLabel: 'Multi Select',
313
+ name: 'updateMultiSelect',
314
+ xtype: 'checkbox'
315
+ }
316
+ ];
317
+
318
+ var combobox = [
319
+ {
320
+ fieldLabel: 'Options',
321
+ name: 'updateOptions',
322
+ xtype: 'textarea',
323
+ labelAlign: 'top',
324
+ labelWidth: 50,
325
+ allowBlank: false,
326
+ width: 235,
327
+ height: 175,
328
+ plugins: [new helpQtip('Add options with a comma separated list. Example: value,Description,option2,Option 2')]
329
+ }
330
+ ];
331
+
332
+ var related_common = [
333
+ {
334
+ fieldLabel: 'Related Model',
335
+ name: 'updateRelatedModel',
336
+ xtype: 'textfield',
337
+ allowBlank: false,
338
+ vtype: 'alphanum',
339
+ plugins: [new helpQtip('Needs to be a valid camel case model class name.')]
340
+ }
341
+ ];
342
+
343
+ var related_combobox = [
344
+ {
345
+ fieldLabel: 'Display Field',
346
+ name: 'updateDisplayField',
347
+ xtype: 'textfield',
348
+ allowBlank: false,
349
+ plugins: [new helpQtip('Needs to be a valid column name on the related model.')]
350
+ }
351
+ ];
352
+
353
+ var related_searchbox = [
354
+ {
355
+ fieldLabel: 'Search Fields',
356
+ name: 'updateSearchFields',
357
+ xtype: 'textfield',
358
+ allowBlank: false,
359
+ plugins: [new helpQtip("Comma separated list of valid columns on the related model. Fields will be searched using OR. Example: 'first_name, last_name'")]
360
+ },
361
+ {
362
+ fieldLabel: 'Display Fields',
363
+ name: 'updateDisplayFields',
364
+ xtype: 'textfield',
365
+ allowBlank: false,
366
+ plugins: [new helpQtip("Comma separated list of valid columns on the related model. Fields are displayed using Display Template. Example: 'first_name, last_name'")]
367
+ },
368
+ {
369
+ fieldLabel: 'Display Template',
370
+ name: 'updateDisplayTemplate',
371
+ xtype: 'textfield',
372
+ allowBlank: false,
373
+ plugins: [new helpQtip("Multiple fields can be displayed as option value. Fields must be included in the list of Display Fields. Example: '{last_name}, {first_name}'")]
374
+ },
375
+ {
376
+ fieldLabel: 'Page Size',
377
+ name: 'updatePageSize',
378
+ xtype: 'numberfield',
379
+ allowBlank: false,
380
+ value: 10,
381
+ plugins: [new helpQtip('Number of results per page.')]
382
+ }
383
+ // {
384
+ // fieldLabel: 'Type Ahead',
385
+ // name: 'updateTypeAhead',
386
+ // xtype: 'checkbox',
387
+ // value: false,
388
+ // plugins: [new helpQtip('Populate and autoselect the remainder of the text being typed after 250 milliseconds if it matches a known value.')]
389
+ // }
390
+ ];
391
+
392
+ var minMaxLength = [
393
+ {
394
+ fieldLabel: 'Min Length',
395
+ name: 'updateMinLength',
396
+ xtype: 'numberfield'
397
+ },
398
+ {
399
+ fieldLabel: 'Max Length',
400
+ name: 'updateMaxLength',
401
+ xtype: 'numberfield'
402
+ }
403
+ ];
404
+
405
+ var numberMinMaxValue = [
406
+ {
407
+ fieldLabel: 'Min Value',
408
+ name: 'updateMinValue',
409
+ xtype: 'numberfield'
410
+ },
411
+ {
412
+ fieldLabel: 'Max Value',
413
+ name: 'updateMaxValue',
414
+ xtype: 'numberfield'
415
+ }
416
+ ];
417
+
418
+ var dateMinMaxValue = [
419
+ {
420
+ fieldLabel: 'Min Value',
421
+ name: 'updateMinValue',
422
+ xtype: 'datefield'
423
+ },
424
+ {
425
+ fieldLabel: 'Max Value',
426
+ name: 'updateMaxValue',
427
+ xtype: 'datefield'
428
+ }
429
+ ];
430
+
431
+ var timeMinMaxValue = [
432
+ {
433
+ fieldLabel: 'Min Value',
434
+ name: 'updateMinValue',
435
+ xtype: 'timefield'
436
+ },
437
+ {
438
+ fieldLabel: 'Max Value',
439
+ name: 'updateMaxValue',
440
+ xtype: 'timefield'
441
+ }
442
+ ];
443
+
444
+ var validation = [
445
+ {
446
+ fieldLabel: 'Validation Type',
447
+ name: 'updateValidationType',
448
+ xtype: 'combobox',
449
+ queryMode: 'local',
450
+ store:[
451
+ ['none','None'],
452
+ ['regex','Regular Expression'],
453
+ ['function','Custom Function'],
454
+ ['vtype','VType']
455
+ ],
456
+ value: 'none',
457
+ forceSelection: true,
458
+ allowBlank: false,
55
459
  listeners:{
56
- 'click':function(button){
57
- var win = button.findParentByType('dynamic_forms_form_builer');
58
- var formPanel = win.findByType('form')[0];
59
- formPanel.getForm().submit({
60
- method:'POST',
61
- waitMsg:'Publishing...',
62
- success:function(form, action){
63
- var response = Ext.util.JSON.decode(action.response.responseText);
64
- win.fireEvent('publish_success', win, response);
65
- win.close();
66
- },
67
- failure:function(form, action){
68
- var response = Ext.util.JSON.decode(action.response.responseText);
69
- win.fireEvent('publish_failure', win, response);
70
- win.close();
71
- }
72
- });
460
+ change: function(field, newValue, oldValue, eOpts){
461
+ var field_props = this.findParentByType('form');
462
+ var updateValidationRegex = field_props.getForm().findField('updateValidationRegex');
463
+ var updateValidationRegexText = field_props.getForm().findField('updateValidationRegexText');
464
+ var updateValidationFunction = field_props.getForm().findField('updateValidationFunction');
465
+ var updateValidationVType = field_props.getForm().findField('updateValidationVType');
466
+ if (newValue == 'regex'){
467
+ updateValidationRegex.show();
468
+ updateValidationRegex.enable();
469
+ updateValidationRegexText.show();
470
+ updateValidationRegexText.enable();
471
+ updateValidationFunction.hide();
472
+ updateValidationFunction.disable();
473
+ updateValidationVType.hide();
474
+ updateValidationVType.disable();
475
+ }else if (newValue == 'function'){
476
+ updateValidationFunction.show();
477
+ updateValidationFunction.enable();
478
+ updateValidationRegex.hide();
479
+ updateValidationRegex.disable();
480
+ updateValidationRegexText.hide();
481
+ updateValidationRegexText.disable();
482
+ updateValidationVType.hide();
483
+ updateValidationVType.disable();
484
+ }else if (newValue == 'vtype'){
485
+ updateValidationVType.show();
486
+ updateValidationVType.enable();
487
+ updateValidationRegex.hide();
488
+ updateValidationRegex.disable();
489
+ updateValidationRegexText.hide();
490
+ updateValidationRegexText.disable();
491
+ updateValidationFunction.hide();
492
+ updateValidationFunction.disable();
493
+ }else{
494
+ updateValidationFunction.hide();
495
+ updateValidationFunction.disable();
496
+ updateValidationRegex.hide();
497
+ updateValidationRegex.disable();
498
+ updateValidationRegexText.disable();
499
+ updateValidationRegexText.hide();
500
+ updateValidationVType.hide();
501
+ updateValidationVType.disable();
502
+ }
73
503
  }
74
504
  }
75
505
  },
76
506
  {
77
- text: 'Cancel',
78
- listeners:{
79
- 'click':function(button){
80
- var win = button.findParentByType('dynamic_forms_form_builer');
81
- var form = win.findByType('form')[0];
82
- form.getForm().reset();
83
- win.close();
507
+ fieldLabel: 'Regex',
508
+ name: 'updateValidationRegex',
509
+ xtype: 'textfield',
510
+ allowBlank: true,
511
+ hidden: true,
512
+ disabled: true
513
+ },
514
+ {
515
+ fieldLabel: 'Regex Text',
516
+ name: 'updateValidationRegexText',
517
+ xtype: 'textfield',
518
+ allowBlank: true,
519
+ hidden: true,
520
+ disabled: true
521
+ },
522
+ {
523
+ fieldLabel: 'Function',
524
+ name: 'updateValidationFunction',
525
+ plugins: [new helpQtip('Call a pre-existing JavaScript function for custom validation. Field value must be passed in using variable v. No semicolon required. Example: customFunction(v)')],
526
+ xtype: 'textfield',
527
+ allowBlank: true,
528
+ hidden: true,
529
+ disabled: true,
530
+ emptyText: 'customFunction(v)'
531
+ },
532
+ {
533
+ fieldLabel: 'VType',
534
+ name: 'updateValidationVType',
535
+ xtype: 'combobox',
536
+ queryMode: 'local',
537
+ store:[
538
+ ['alpha','Alpha'],
539
+ ['alphanum','Alphanumeric'],
540
+ ['email','Email'],
541
+ ['IPAddress','IP Address'],
542
+ ['url','URL']
543
+ ],
544
+ plugins: [new helpQtip('Use a built-in or custom ExtJS VType.')],
545
+ editable: true,
546
+ forceSelection: false,
547
+ hidden: true,
548
+ disabled: true,
549
+ allowBlank: true
550
+ }
551
+ ];
552
+
553
+ var hideMode = [
554
+ {
555
+ fieldLabel: 'Hide Mode',
556
+ name: 'updateHideMode',
557
+ xtype: 'combobox',
558
+ queryMode: 'local',
559
+ store:[
560
+ ['display','Display'],
561
+ ['visibility','Visibility'],
562
+ ['offsets','Offsets']
563
+ ],
564
+ value: 'display',
565
+ plugins: [new helpQtip("A String which specifies how this Component's encapsulating DOM element will be hidden. Values may be:<br /> 'display' : The Component will be hidden using the display: none style.<br /> 'visibility' : The Component will be hidden using the visibility: hidden style.<br /> 'offsets' : The Component will be hidden by absolutely positioning it out of the visible area of the document. This is useful when a hidden Component must maintain measurable dimensions. Hiding using display results in a Component having zero dimensions.<br /> Defaults to: 'display'")],
566
+ editable: false,
567
+ forceSelection: true,
568
+ allowBlank: true
569
+ }
570
+ ];
571
+
572
+ var hideTrigger = [
573
+ {
574
+ fieldLabel: 'Hide Trigger',
575
+ name: 'updateHideTrigger',
576
+ xtype: 'checkbox',
577
+ plugins: [new helpQtip('Hide the trigger element and display only the base text field.')]
578
+ }
579
+ ];
580
+
581
+ var result = [];
582
+ if (Ext.isEmpty(field_xtype)){
583
+ result = result.concat(base_top);
584
+ result = result.concat(common);
585
+ result = result.concat(base_bottom);
586
+ }else if (field_xtype == 'hiddenfield'){
587
+ result = result.concat(base_top);
588
+ result = result.concat(base_bottom);
589
+ result = result.concat(hideMode);
590
+ return result;
591
+ }
592
+ switch(xtype){
593
+ case 'related_combobox':
594
+ result = result.concat(common_combobox);
595
+ result = result.concat(hideTrigger);
596
+ result = result.concat(related_common);
597
+ result = result.concat(related_combobox);
598
+ break;
599
+ case 'related_searchbox':
600
+ result = result.concat(common_combobox);
601
+ result = result.concat(related_common);
602
+ result = result.concat(related_searchbox);
603
+ break;
604
+ case 'combo':
605
+ result = result.concat(common_combobox);
606
+ result = result.concat(hideTrigger);
607
+ result = result.concat(combobox);
608
+ break;
609
+ case 'combobox':
610
+ result = result.concat(common_combobox);
611
+ result = result.concat(hideTrigger);
612
+ result = result.concat(combobox);
613
+ break;
614
+ case 'datefield':
615
+ result = result.concat(hideTrigger);
616
+ result = result.concat(dateMinMaxValue);
617
+ result = result.concat(validation);
618
+ break;
619
+ case 'email':
620
+ result = result.concat(minMaxLength);
621
+ result = result.concat(validation);
622
+ break;
623
+ case 'filefield':
624
+ result = result.concat(filefield);
625
+ result = result.concat(hideTrigger);
626
+ result = result.concat(validation);
627
+ break;
628
+ case 'numberfield':
629
+ result = result.concat(hideTrigger);
630
+ result = result.concat(minMaxLength);
631
+ result = result.concat(numberMinMaxValue);
632
+ result = result.concat(validation);
633
+ break;
634
+ case 'password':
635
+ result = result.concat(minMaxLength);
636
+ result = result.concat(validation);
637
+ break;
638
+ case 'textfield':
639
+ result = result.concat(minMaxLength);
640
+ result = result.concat(validation);
641
+ break;
642
+ case 'textarea':
643
+ result = result.concat(minMaxLength);
644
+ result = result.concat(validation);
645
+ break;
646
+ case 'timefield':
647
+ result = result.concat(hideTrigger);
648
+ result = result.concat(timeMinMaxValue);
649
+ result = result.concat(validation);
650
+ break;
651
+ default:
652
+ }
653
+
654
+ return result;
655
+ },
656
+
657
+ validateFieldNameUnique : function(formPanel, fieldName){
658
+ return ((this.getIndexOfFieldByName(formPanel, fieldName) < 0) ? true : false);
659
+ },
660
+
661
+ getIndexOfFieldByName : function(formPanel, fieldName){
662
+ for (var i = 0; i < formPanel.form_definition.length; i++) {
663
+ if (formPanel.form_definition[i].name == fieldName){
664
+ return i;
665
+ }
666
+ }
667
+ return -1;
668
+ },
669
+
670
+ moveField : function(formPanel, direction){
671
+ if (Ext.isEmpty(formPanel.selected_field)){
672
+ Ext.Msg.alert('Error', 'Please select a field to move.');
673
+ }else{
674
+ var i = 0;
675
+ var field_in_definition = null;
676
+ // find selected field in definition to remove it
677
+ Ext.each(formPanel.form_definition, function(field){
678
+ if (field.name == formPanel.selected_field.name){
679
+ idx = i;
680
+ field_in_definition = field;
681
+ }
682
+ i++;
683
+ });
684
+ if (direction == 'up' && idx === 0){
685
+ Ext.Msg.alert('Error', 'Cannot move. Field is already at top.');
686
+ }else if (direction == 'down' && idx == (formPanel.form_definition.length-1)){
687
+ Ext.Msg.alert('Error', 'Cannot move. Field is already at bottom.');
688
+ }else{
689
+ var new_index = (direction == 'up' ? idx-1 : idx+1);
690
+ formPanel.form_definition.splice(idx, 1); // remove field from definition
691
+ formPanel.form_definition.splice(new_index, 0, field_in_definition); // add field to definition
692
+ formPanel.findParentByType('dynamic_forms_FormBuilder').reloadForm(formPanel); // redraw form from definition
693
+ formPanel.getForm().findField(formPanel.selected_field.name).getEl().dom.click(); // highlight selected field
694
+ }
695
+ }
696
+ },
697
+
698
+ emailRegex : function(){
699
+ return ErpTechSvcs.Config.email_regex;
700
+ },
701
+
702
+ addFieldToForm : function(formPanel, fieldDefinition){
703
+ if (fieldDefinition) formPanel.form_definition.push(fieldDefinition);
704
+ this.reloadForm(formPanel);
705
+ // highlight newly added field
706
+ if (fieldDefinition) formPanel.getForm().findField(fieldDefinition.name).getEl().dom.click();
707
+ },
708
+
709
+ addValidationToField : function(field){
710
+ if(!Ext.isEmpty(field.validation_regex)){
711
+ field.regex = initRegex(field.validation_regex);
712
+ }else if(!Ext.isEmpty(field.validator_function)){
713
+ field.validator = function(v){ return eval(field.validator_function); };
714
+ }
715
+ return field;
716
+ },
717
+
718
+ addHelpQtipToField : function(field){
719
+ if(!Ext.isEmpty(field.help_qtip)){
720
+ field.plugins = [new helpQtip(field.help_qtip)];
721
+ }
722
+ return field;
723
+ },
724
+
725
+ convertHiddenFieldToDisplayFieldForUi : function(field){
726
+ if (field.xtype == 'hiddenfield'){
727
+ field.xtype = 'displayfield';
728
+ field.field_xtype = 'hiddenfield';
729
+ }
730
+ return field;
731
+ },
732
+
733
+ // alterFileUploadField : function(field){
734
+ // if (field.xtype == 'filefield'){
735
+ // console.log('filefield');
736
+ // field.listeners = {
737
+ // 'render': function(field){
738
+ // console.log('listener');
739
+ // field.inputEl.dom.size = 20;
740
+ // }
741
+ // };
742
+ // }
743
+ // return field;
744
+ // },
745
+
746
+ reloadForm : function(formPanel){
747
+ var self = this;
748
+ formPanel.removeAll();
749
+ var form_definition_copy = Ext.clone(formPanel.form_definition); // make independent copy
750
+ Ext.each(form_definition_copy, function(field){
751
+ field = self.convertHiddenFieldToDisplayFieldForUi(field);
752
+ field = self.addValidationToField(field);
753
+ field = self.addHelpQtipToField(field);
754
+ //field = self.alterFileUploadField(field);
755
+ field = self.addHighlightListenerForSelectedField(field);
756
+ });
757
+ formPanel.add(form_definition_copy);
758
+ },
759
+
760
+ addHighlightListenerForSelectedField : function(field){
761
+ field.listeners = {
762
+ render: function(item){
763
+ var el = item.getEl();
764
+ el.addListener('click', function(e, t, eOpts){
765
+ var formPanel = item.findParentByType('form');
766
+ var highlight_border = '1px solid green';
767
+ //console.log(el.dom.style.border);
768
+ if (el.dom.style.border != highlight_border){
769
+ Ext.each(formPanel.items.items, function(i){
770
+ //console.log(i.getEl().getStyle('border'));
771
+ if (item != i && i.getEl().dom.style.border == highlight_border){
772
+ var label = i.getEl().query('label').first();
773
+ label.style.width = (parseInt(label.style.width, 10) + 2) + 'px';
774
+ i.getEl().setStyle('border', 'none');
775
+ }
776
+ });
777
+ var label = el.query('label').first();
778
+ label.style.width = (parseInt(label.style.width, 10) - 2) + 'px';
779
+ el.setStyle('border', highlight_border);
780
+ el.highlight();
781
+
782
+ // set field properties as active tab
783
+ var formBuilder = formPanel.findParentByType('dynamic_forms_FormBuilder');
784
+ var east_tabs = formBuilder.query('#east_tabs').first();
785
+ east_tabs.setActiveTab('field_props');
786
+
787
+ formPanel.selected_field = item;
788
+
789
+ // populate field properties
790
+ var prop_formPanel = east_tabs.query('#field_props').first();
791
+ var prop_form = prop_formPanel.getForm();
792
+ prop_formPanel.removeAll();
793
+ prop_formPanel.add(formBuilder.getFieldOptionsForField(item));
794
+
795
+ // common
796
+ try { prop_form.findField('updateFieldType').setValue(item.xtype); } catch(e) {}
797
+ try { prop_form.findField('updateName').setValue(item.name); } catch(e) {}
798
+ try { prop_form.findField('updateLabel').setValue(item.fieldLabel); } catch(e) {}
799
+ try { prop_form.findField('updateLabelAlign').setValue(item.labelAlign); } catch(e) {}
800
+ try { var updateValue = ((item.xtype == 'related_combobox') ? item.default_value : item.value);
801
+ prop_form.findField('updateValue').setValue(updateValue); } catch(e) {}
802
+ try { var updateValue = ((item.xtype == 'related_searchbox') ? item.default_value : item.value);
803
+ prop_form.findField('updateValue').setValue(updateValue); } catch(e) {}
804
+ try { prop_form.findField('updateEmptyText').setValue(item.emptyText); } catch(e) {}
805
+ try { prop_form.findField('updateHelpQtip').setValue(item.help_qtip); } catch(e) {}
806
+ try { prop_form.findField('updateAllowBlank').setValue(item.allowBlank); } catch(e) {}
807
+ try { prop_form.findField('updateDisplayInGrid').setValue(item.display_in_grid); } catch(e) {}
808
+ try { prop_form.findField('updateSearchable').setValue(item.searchable); } catch(e) {}
809
+ try { prop_form.findField('updateReadOnly').setValue(item.readOnly); } catch(e) {}
810
+ try { prop_form.findField('updateWidth').setValue(item.width); } catch(e) {}
811
+ try { prop_form.findField('updateHeight').setValue(item.height); } catch(e) {}
812
+ try { prop_form.findField('updateLabelWidth').setValue(item.labelWidth); } catch(e) {}
813
+ try { prop_form.findField('updateHideTrigger').setValue(item.hideTrigger); } catch(e) {}
814
+ try { prop_form.findField('updateHideMode').setValue(item.hideMode); } catch(e) {}
815
+
816
+ if (item.xtype == 'datefield' || item.xtype == 'timefield'){
817
+ prop_form.findField('updateMinValue').setValue(item.minValue);
818
+ prop_form.findField('updateMaxValue').setValue(item.maxValue);
819
+ }
820
+
821
+ if(!Ext.isEmpty(item.regex)){
822
+ prop_form.findField('updateValidationType').setValue('regex');
823
+ prop_form.findField('updateValidationRegex').setValue(item.regex);
824
+ if(!Ext.isEmpty(item.regexText)) prop_form.findField('updateValidationRegexText').setValue(item.regexText);
825
+ }else if(!Ext.isEmpty(item.validator_function)){
826
+ prop_form.findField('updateValidationType').setValue('function');
827
+ prop_form.findField('updateValidationFunction').setValue(item.validator_function);
828
+ }else if(!Ext.isEmpty(item.vtype)){
829
+ prop_form.findField('updateValidationType').setValue('vtype');
830
+ prop_form.findField('updateValidationVType').setValue(item.vtype);
831
+ }
832
+
833
+ if (item.xtype == 'numberfield'){
834
+ if (item.minValue != Number.NEGATIVE_INFINITY){
835
+ prop_form.findField('updateMinValue').setValue(item.minValue);
836
+ }
837
+ if (item.maxValue != Number.MAX_VALUE){
838
+ prop_form.findField('updateMaxValue').setValue(item.maxValue);
839
+ }
840
+ }
841
+
842
+ if (item.xtype == 'textfield' || item.xtype == 'textarea' || item.xtype == 'numberfield'){
843
+ prop_form.findField('updateMinLength').setValue(item.minLength);
844
+ if (item.maxLength != Number.MAX_VALUE){
845
+ prop_form.findField('updateMaxLength').setValue(item.maxLength);
846
+ }
847
+ }
848
+
849
+ if (item.xtype == 'related_combobox' || item.xtype == 'related_searchbox'){
850
+ prop_form.findField('updateEditable').setValue(item.editable);
851
+ prop_form.findField('updateForceSelection').setValue(item.forceSelection);
852
+ prop_form.findField('updateMultiSelect').setValue(item.multiSelect);
853
+ try { prop_form.findField('updateRelatedModel').setValue(item.extraParams.model); } catch(e) {}
854
+ if (item.xtype == 'related_combobox'){
855
+ prop_form.findField('updateDisplayField').setValue(item.displayField);
856
+ }else{
857
+ prop_form.findField('updateSearchFields').setValue(item.search_fields);
858
+ prop_form.findField('updateDisplayFields').setValue(item.display_fields);
859
+ prop_form.findField('updateDisplayTemplate').setValue(item.display_template);
860
+ //prop_form.findField('updateTypeAhead').setValue(item.typeAhead);
861
+ prop_form.findField('updatePageSize').setValue(item.pageSize);
862
+ }
863
+ }else if (item.xtype == 'combobox' || item.xtype == 'combo'){
864
+ var options = Ext.encode(item.getStore().proxy.reader.rawData).replace(/\"/g,'').replace(/\[/g,'').replace(/\]/g,'');
865
+ prop_form.findField('updateOptions').setValue(options == 'null' ? '' : options);
866
+ prop_form.findField('updateEditable').setValue(item.editable);
867
+ prop_form.findField('updateForceSelection').setValue(item.forceSelection);
868
+ prop_form.findField('updateMultiSelect').setValue(item.multiSelect);
869
+ }
870
+
871
+ if (item.xtype == 'filefield'){
872
+ prop_form.findField('updateButtonText').setValue(item.buttonText);
873
+ }
874
+
84
875
  }
876
+ });
877
+ }
878
+ };
879
+
880
+ return field;
881
+ },
882
+
883
+ constructor : function(config) {
884
+ if (Ext.isEmpty(config.form_definition)) config.form_definition = [];
885
+
886
+ config = Ext.apply({
887
+ id: 'formBuilder_'+config.title,
888
+ layout:'border',
889
+ title: config.title || 'New Form',
890
+ border: false,
891
+ closable: true,
892
+ autoHeight:true,
893
+ buttonAlign:'center',
894
+ items: [{
895
+ xtype: 'form',
896
+ itemId: 'dynamicForm',
897
+ region: 'center',
898
+ autoScroll: true,
899
+ bodyPadding: 10,
900
+ form_definition: config.form_definition,
901
+ form_id: (Ext.isEmpty(config.form_id) ? null : config.form_id),
902
+ defaults:{
903
+ msgTarget: (Ext.isEmpty(config.msg_target) ? 'left' : config.msg_target)
904
+ },
905
+ tbar: [
906
+ { xtype: 'button',
907
+ text: 'Save Form',
908
+ iconCls: 'icon-save',
909
+ listeners:{
910
+ click: function(button){
911
+ var formPanel = button.findParentByType('form');
912
+ var formBuilder = formPanel.findParentByType('dynamic_forms_FormBuilder');
913
+ var form_props = formBuilder.query('#form_props').first().getForm();
914
+
915
+ if (form_props.isValid()){
916
+ var create = Ext.isEmpty(config.form_id);
917
+ formBuilder.setWindowStatus('Saving form ...');
918
+ Ext.Ajax.request({
919
+ url: (create === true ? '/erp_forms/erp_app/desktop/dynamic_forms/forms/create' : '/erp_forms/erp_app/desktop/dynamic_forms/forms/update'),
920
+ method: 'POST',
921
+ params:{
922
+ id:config.form_id,
923
+ form_definition:Ext.JSON.encode(formPanel.form_definition),
924
+ description: form_props.findField('description').getValue(),
925
+ model_name: config.model_name,
926
+ widget_action: form_props.findField('widget_action').getValue(),
927
+ widget_email_recipients: form_props.findField('widget_email_recipients').getValue(),
928
+ focus_first_field: form_props.findField('focus_first_field').getValue(),
929
+ submit_empty_text: form_props.findField('submit_empty_text').getValue(),
930
+ msg_target: form_props.findField('msg_target').getValue(),
931
+ submit_button_label: form_props.findField('submit_button_label').getValue(),
932
+ cancel_button_label: form_props.findField('cancel_button_label').getValue(),
933
+ comment: form_props.findField('comment').getValue()
934
+ },
935
+ success: function(response) {
936
+ formBuilder.clearWindowStatus();
937
+ var obj = Ext.decode(response.responseText);
938
+ if(obj.success){
939
+ if (create === true){
940
+ Ext.getCmp('dynamic_formsTabPanel').remove(formBuilder);
941
+ Ext.getStore('dynamicFormStore').load({ params:{ id: obj.id } });
942
+ Ext.getStore('formsTreeStore').load();
943
+ }else{
944
+ formBuilder.setTitle(form_props.findField('description').getValue());
945
+ //Ext.Msg.alert('Success', 'Form saved.');
946
+ }
947
+ }
948
+ else{
949
+ Ext.Msg.alert('Error', 'Error saving form.');
950
+ }
951
+ },
952
+ failure: function(response) {
953
+ formBuilder.clearWindowStatus();
954
+ Ext.Msg.alert('Error', 'Error saving form');
955
+ }
956
+ });
957
+ }else{
958
+ var east_tabs = formBuilder.query('#east_tabs').first();
959
+ east_tabs.setActiveTab('form_props');
960
+ Ext.Msg.alert('Error', "There is a validation error with this form's properties. Please correct fields marked red.");
961
+ }
962
+ }
963
+ }
964
+ },
965
+ { xtype: 'button',
966
+ text: 'View Definition',
967
+ iconCls: 'icon-document',
968
+ listeners:{
969
+ click: function(button){
970
+ var formPanel = button.findParentByType('form');
971
+ var form_definition = Ext.encode(formPanel.form_definition).replace(/,/gi,', ').replace(/\},/gi,'},<br />');
972
+ // popup window panel with form definition
973
+ //Ext.MessageBox.minWidth = 600;
974
+ //var alertBox = Ext.create("Ext.MessageBox",{ width: 600 });
975
+ //Ext.MessageBox.alert('Form Definition', );
976
+
977
+ var defWindow = Ext.create("Ext.window.Window",{
978
+ layout:'fit',
979
+ title:'Form Definition',
980
+ //plain: true,
981
+ buttonAlign:'center',
982
+ items: Ext.create("Ext.panel.Panel",{
983
+ bodyStyle:'padding:5px 5px 0',
984
+ html: form_definition
985
+ }),
986
+ buttons: [{
987
+ text:'Close',
988
+ listeners:{
989
+ 'click':function(button){
990
+ defWindow.close();
991
+ }
992
+ }
993
+ }]
994
+ });
995
+ defWindow.show();
996
+ }
997
+ }
998
+ },
999
+ { xtype: 'button',
1000
+ text: 'Move Field Up',
1001
+ iconCls: 'icon-arrow-up-blue',
1002
+ listeners:{
1003
+ click: function(button){
1004
+ var formPanel = button.findParentByType('form');
1005
+ formPanel.findParentByType('dynamic_forms_FormBuilder').moveField(formPanel, 'up');
1006
+ }
1007
+ }
1008
+ },
1009
+ { xtype: 'button',
1010
+ text: 'Move Field Down',
1011
+ iconCls: 'icon-arrow-down-blue',
1012
+ listeners:{
1013
+ click: function(button){
1014
+ var formPanel = button.findParentByType('form');
1015
+ formPanel.findParentByType('dynamic_forms_FormBuilder').moveField(formPanel, 'down');
1016
+ }
1017
+ }
1018
+ },
1019
+ { xtype: 'button',
1020
+ text: 'Remove Field',
1021
+ iconCls: 'icon-delete',
1022
+ listeners:{
1023
+ click: function(button){
1024
+ var formPanel = button.findParentByType('form');
1025
+
1026
+ if (Ext.isEmpty(formPanel.selected_field)){
1027
+ Ext.Msg.alert('Error', 'Please select a field to remove.');
1028
+ }else{
1029
+ Ext.MessageBox.confirm('Confirm', 'Are you sure you want to remove this field?',
1030
+ function(btn){
1031
+ if(btn == 'no'){
1032
+ return false;
1033
+ }
1034
+ else if(btn == 'yes')
1035
+ {
1036
+ var i = 0;
1037
+ // find selected field in definition to remove it
1038
+ Ext.each(formPanel.form_definition, function(field){
1039
+ if (field.name == formPanel.selected_field.name){ idx = i; }
1040
+ i++;
1041
+ });
1042
+ formPanel.form_definition.splice(idx, 1); // remove field from definition
1043
+ formPanel.selected_field = null; // deselect field that was removed
1044
+ formPanel.findParentByType('dynamic_forms_FormBuilder').reloadForm(formPanel); // redraw form from definition
1045
+ }
1046
+ }
1047
+ );
1048
+ }
1049
+ }
1050
+ }
1051
+ }
1052
+ ],
1053
+ listeners:{
1054
+ render:function(formPanel){
1055
+ formPanel.findParentByType('dynamic_forms_FormBuilder').reloadForm(formPanel);
1056
+ var formPanelDropTargetEl = formPanel.body.dom;
1057
+ var formPanelDropTarget = Ext.create('Ext.dd.DropTarget', formPanelDropTargetEl, {
1058
+ ddGroup: 'fieldsDDGroup',
1059
+ notifyEnter: function(ddSource, e, data) {
1060
+ formPanel.body.stopAnimation();
1061
+ formPanel.body.highlight();
1062
+ },
1063
+ notifyDrop : function(ddSource, e, data){
1064
+ var droppedField = data.records[0];
1065
+
1066
+ var addFieldWindow = Ext.create("Ext.window.Window",{
1067
+ layout:'fit',
1068
+ width:375,
1069
+ title:'Add Field to Form',
1070
+ height:100,
1071
+ plain: true,
1072
+ buttonAlign:'center',
1073
+ items: Ext.create("Ext.form.Panel",{
1074
+ labelWidth: 110,
1075
+ frame:false,
1076
+ bodyStyle:'padding:5px 5px 0',
1077
+ defaults: {
1078
+ width: 225
1079
+ },
1080
+ items: [
1081
+ {
1082
+ xtype:'textfield',
1083
+ fieldLabel:'Field Name',
1084
+ allowBlank:false,
1085
+ name:'field_name',
1086
+ value: (droppedField.get('field_xtype') == 'filefield' ? 'file' : ''),
1087
+ readOnly: (droppedField.get('field_xtype') == 'filefield' ? true : false),
1088
+ maskRe: /^\w+$/,
1089
+ regex: /^\w+$/,
1090
+ plugins: [new helpQtip('Only letters, numbers and underscores are valid. Field Names must be unique. A File Upload field must be named "file".')],
1091
+ listeners:{
1092
+ afterrender:function(field){
1093
+ field.focus(false, 200);
1094
+ },
1095
+ 'specialkey': function(field, e){
1096
+ if (e.getKey() == e.ENTER) {
1097
+ var button = field.findParentByType('window').query('#submitButton').first();
1098
+ button.fireEvent('click', button);
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ ]
1104
+ }),
1105
+ buttons: [{
1106
+ itemId: 'submitButton',
1107
+ text:'Submit',
1108
+ listeners:{
1109
+ 'click':function(button){
1110
+ var window = button.findParentByType('window');
1111
+ var addFieldFormPanel = window.query('form')[0];
1112
+ var field_name = addFieldFormPanel.getForm().findField('field_name').getValue();
1113
+ var formBuilder = formPanel.findParentByType('dynamic_forms_FormBuilder');
1114
+
1115
+ if (!addFieldFormPanel.getForm().isValid()){
1116
+ Ext.Msg.alert('Error', 'Please correct form.');
1117
+ return;
1118
+ } else if (field_name == 'text'){
1119
+ Ext.Msg.alert('Error', 'Field Name cannot be "text".');
1120
+ return;
1121
+ } else if (!formBuilder.validateFieldNameUnique(formPanel, field_name)){
1122
+ Ext.Msg.alert('Error', 'Field Name must be unique.');
1123
+ return;
1124
+ }
1125
+
1126
+ var fieldDefinition = {
1127
+ xtype: droppedField.get('field_xtype'),
1128
+ name: field_name,
1129
+ fieldLabel: (droppedField.get('field_xtype') == 'hiddenfield' ? 'Hidden Field' : field_name.titleize()),
1130
+ display_in_grid: true,
1131
+ searchable: true,
1132
+ labelWidth: 75
1133
+ };
1134
+
1135
+ switch(fieldDefinition.xtype){
1136
+ case 'hiddenfield':
1137
+ fieldDefinition.display_in_grid = false;
1138
+ fieldDefinition.searchable = false;
1139
+ break;
1140
+ case 'related_combobox':
1141
+ fieldDefinition.width = 175;
1142
+ fieldDefinition.editable = true;
1143
+ fieldDefinition.forceSelection = true;
1144
+ break;
1145
+ case 'related_searchbox':
1146
+ fieldDefinition.width = 350;
1147
+ fieldDefinition.editable = true;
1148
+ fieldDefinition.forceSelection = true;
1149
+ //fieldDefinition.typeAhead = true;
1150
+ fieldDefinition.pageSize = 10;
1151
+ break;
1152
+ case 'checkbox':
1153
+ fieldDefinition.inputValue = true;
1154
+ fieldDefinition.uncheckedValue = false;
1155
+ break;
1156
+ case 'combobox':
1157
+ fieldDefinition.editable = true;
1158
+ fieldDefinition.forceSelection = true;
1159
+ break;
1160
+ case 'yesno':
1161
+ fieldDefinition.xtype = 'combobox';
1162
+ fieldDefinition.forceSelection = true;
1163
+ fieldDefinition.store = [['no','No'],['yes','Yes']];
1164
+ break;
1165
+ case 'email':
1166
+ fieldDefinition.xtype = 'textfield';
1167
+ fieldDefinition.validator_function = 'validateEmail(v)';
1168
+ break;
1169
+ case 'password':
1170
+ fieldDefinition.xtype = 'textfield';
1171
+ fieldDefinition.inputType = 'password';
1172
+ break;
1173
+ case 'filefield':
1174
+ fieldDefinition.vtype = 'file';
1175
+ fieldDefinition.name = 'file';
1176
+ // fieldDefinition.inputType = 'file'; // needed for fileSize validation but it causes some cosmetic problems
1177
+ // fieldDefinition.buttonConfig = {hidden: true};
1178
+ break;
1179
+ default:
1180
+ }
1181
+
1182
+ formBuilder.addFieldToForm(formPanel, fieldDefinition);
1183
+
1184
+ addFieldWindow.close();
1185
+ }
1186
+ }
1187
+ },{
1188
+ text: 'Close',
1189
+ handler: function(){
1190
+ addFieldWindow.close();
1191
+ }
1192
+ }]
1193
+ });
1194
+ addFieldWindow.show();
1195
+
1196
+ return true;
1197
+ }
1198
+ });
1199
+ }
1200
+ }
1201
+ },
1202
+ {
1203
+ xtype: 'tabpanel',
1204
+ itemId: 'east_tabs',
1205
+ region: 'east',
1206
+ width: 275,
1207
+ activeTab: 0,
1208
+ defaults:{
1209
+ width: 255
1210
+ },
1211
+ items: [
1212
+ {
1213
+ xtype: 'form',
1214
+ title: 'Field Properties',
1215
+ itemId: 'field_props',
1216
+ autoScroll: true,
1217
+ bodyPadding: 10,
1218
+ tbar: [
1219
+ { xtype: 'button',
1220
+ text: 'Update Field',
1221
+ iconCls: 'icon-edit',
1222
+
1223
+ listeners:{
1224
+ click: function(button){
1225
+ // get formPanel
1226
+ var updateFieldForm = button.findParentByType('form').getForm();
1227
+ if (updateFieldForm.isValid()){
1228
+ var formPanel = Ext.getCmp('formBuilder_'+config.title).query('#dynamicForm').first();
1229
+ var formBuilder = formPanel.findParentByType('dynamic_forms_FormBuilder');
1230
+ var selected_field = formPanel.selected_field;
1231
+ var updateName = updateFieldForm.findField('updateName').getValue();
1232
+
1233
+ // build field json
1234
+ var fieldDefinition = {
1235
+ xtype: (selected_field.field_xtype == 'hiddenfield' ? 'hiddenfield' : selected_field.xtype),
1236
+ name: updateName,
1237
+ fieldLabel: updateFieldForm.findField('updateLabel').getValue()
1238
+ };
1239
+ if (selected_field.field_xtype == 'hiddenfield'){
1240
+ try { var updateHideMode = updateFieldForm.findField('updateHideMode').getValue();
1241
+ if (!Ext.isEmpty(updateHideMode)) fieldDefinition.hideMode = updateHideMode; } catch(e){}
1242
+ }
1243
+ try { fieldDefinition.labelAlign = updateFieldForm.findField('updateLabelAlign').getValue(); } catch(e){}
1244
+ try { fieldDefinition.readOnly = updateFieldForm.findField('updateReadOnly').getValue(); } catch(e){}
1245
+ try { fieldDefinition.hideTrigger = updateFieldForm.findField('updateHideTrigger').getValue(); } catch(e){}
1246
+ try { var updateEmptyText = updateFieldForm.findField('updateEmptyText').getValue();
1247
+ if (!Ext.isEmpty(updateEmptyText)) fieldDefinition.emptyText = updateEmptyText; } catch(e){}
1248
+ try { var updateHelpQtip = updateFieldForm.findField('updateHelpQtip').getValue();
1249
+ if (!Ext.isEmpty(updateHelpQtip)) fieldDefinition.help_qtip = updateHelpQtip; } catch(e){}
1250
+
1251
+ try { fieldDefinition.allowBlank = updateFieldForm.findField('updateAllowBlank').getValue(); } catch(e){}
1252
+ try { fieldDefinition.display_in_grid = updateFieldForm.findField('updateDisplayInGrid').getValue(); } catch(e){}
1253
+ try { fieldDefinition.searchable = updateFieldForm.findField('updateSearchable').getValue(); } catch(e){}
1254
+ try { var updateValue = updateFieldForm.findField('updateValue').getValue();
1255
+ if (selected_field.xtype == 'related_combobox' || selected_field.xtype == 'related_searchbox') {
1256
+ if (!Ext.isEmpty(updateValue)) fieldDefinition.default_value = parseInt(updateValue, 10);
1257
+ }else{
1258
+ if (!Ext.isEmpty(updateValue)) fieldDefinition.value = updateValue;
1259
+ }
1260
+ } catch(e){}
1261
+ try { var updateLabelWidth = updateFieldForm.findField('updateLabelWidth').getValue();
1262
+ if (!Ext.isEmpty(updateLabelWidth)) fieldDefinition.labelWidth = updateLabelWidth; } catch(e){}
1263
+ try { var updateWidth = updateFieldForm.findField('updateWidth').getValue();
1264
+ if (!Ext.isEmpty(updateWidth)) fieldDefinition.width = updateWidth; } catch(e){}
1265
+ try { var updateHeight = updateFieldForm.findField('updateHeight').getValue();
1266
+ if (!Ext.isEmpty(updateHeight)) fieldDefinition.height = updateHeight; } catch(e){}
1267
+
1268
+ if (Ext.isEmpty(selected_field.field_xtype) && !Ext.Array.indexOf(['related_combobox','related_searchbox','combobox','combo'], selected_field.xtype)){
1269
+ switch(updateFieldForm.findField('updateValidationType').getValue()){
1270
+ case 'regex':
1271
+ var validationRegex = updateFieldForm.findField('updateValidationRegex').getValue();
1272
+ if(!Ext.isEmpty(validationRegex)) fieldDefinition.validation_regex = validationRegex;
1273
+ fieldDefinition.regexText = updateFieldForm.findField('updateValidationRegexText').getValue();
1274
+ break;
1275
+ case 'function':
1276
+ fieldDefinition.validator_function = updateFieldForm.findField('updateValidationFunction').getValue();
1277
+ break;
1278
+ case 'vtype':
1279
+ fieldDefinition.vtype = updateFieldForm.findField('updateValidationVType').getValue();
1280
+ break;
1281
+ default:
1282
+ }
1283
+ }
1284
+
1285
+ if (selected_field.xtype == 'datefield' || selected_field.xtype == 'timefield' || selected_field.xtype == 'numberfield'){
1286
+ var updateMinValue = updateFieldForm.findField('updateMinValue').getValue();
1287
+ var updateMaxValue = updateFieldForm.findField('updateMaxValue').getValue();
1288
+ if(!Ext.isEmpty(updateMinValue)) fieldDefinition.minValue = updateMinValue;
1289
+ if(!Ext.isEmpty(updateMaxValue)) fieldDefinition.maxValue = updateMaxValue;
1290
+ }
1291
+
1292
+ if (selected_field.xtype == 'textfield' || selected_field.xtype == 'textarea' || selected_field.xtype == 'numberfield'){
1293
+ var updateMinLength = updateFieldForm.findField('updateMinLength').getValue();
1294
+ var updateMaxLength = updateFieldForm.findField('updateMaxLength').getValue();
1295
+ if(!Ext.isEmpty(updateMinLength)) fieldDefinition.minLength = updateMinLength;
1296
+ if(!Ext.isEmpty(updateMaxLength)) fieldDefinition.maxLength = updateMaxLength;
1297
+ }
1298
+
1299
+ if (selected_field.xtype == 'filefield'){
1300
+ fieldDefinition.buttonText = updateFieldForm.findField('updateButtonText').getValue();
1301
+ fieldDefinition.vtype = 'file';
1302
+ // fieldDefinition.inputType = 'file'; // needed for fileSize validation but it causes some cosmetic problems
1303
+ // fieldDefinition.buttonConfig = {hidden: true};
1304
+ }
1305
+
1306
+ if (selected_field.xtype == 'related_combobox' || selected_field.xtype == 'related_searchbox'){
1307
+ fieldDefinition.editable = updateFieldForm.findField('updateEditable').getValue();
1308
+ fieldDefinition.forceSelection = updateFieldForm.findField('updateForceSelection').getValue();
1309
+ fieldDefinition.multiSelect = updateFieldForm.findField('updateMultiSelect').getValue();
1310
+ fieldDefinition.extraParams = {
1311
+ model: updateFieldForm.findField('updateRelatedModel').getValue()
1312
+ };
1313
+ if (selected_field.xtype == 'related_combobox'){
1314
+ fieldDefinition.fields = [
1315
+ { name: 'id' },
1316
+ { name: fieldDefinition.displayField }
1317
+ ];
1318
+ fieldDefinition.displayField = updateFieldForm.findField('updateDisplayField').getValue();
1319
+ fieldDefinition.extraParams.displayField = fieldDefinition.displayField;
1320
+ }else if (selected_field.xtype == 'related_searchbox'){
1321
+ fieldDefinition.search_fields = updateFieldForm.findField('updateSearchFields').getValue().replace(/\s/g,'');
1322
+ fieldDefinition.display_fields = updateFieldForm.findField('updateDisplayFields').getValue().replace(/\s/g,'');
1323
+ fieldDefinition.display_template = updateFieldForm.findField('updateDisplayTemplate').getValue();
1324
+ //fieldDefinition.typeAhead = updateFieldForm.findField('updateTypeAhead').getValue();
1325
+ fieldDefinition.pageSize = updateFieldForm.findField('updatePageSize').getValue();
1326
+ fieldDefinition.fields = [{ name: 'id' }];
1327
+ Ext.each(fieldDefinition.display_fields.split(','), function(f){
1328
+ fieldDefinition.fields.push({ name: f });
1329
+ });
1330
+ fieldDefinition.extraParams.search_fields = fieldDefinition.search_fields;
1331
+ fieldDefinition.extraParams.display_fields = fieldDefinition.display_fields;
1332
+ }
1333
+ }else if (selected_field.xtype == 'combobox' || selected_field.xtype == 'combo'){
1334
+ var updateOptions = updateFieldForm.findField('updateOptions').getValue();
1335
+ if(updateOptions){
1336
+ var options = updateOptions.split(',');
1337
+ var optionsArray = [], subArray = [], i = 1;
1338
+ Ext.each(options, function(option){
1339
+ subArray.push(option.trim());
1340
+ if (i%2 === 0){
1341
+ optionsArray.push(subArray);
1342
+ subArray = [];
1343
+ }
1344
+ i++;
1345
+ });
1346
+
1347
+ fieldDefinition.store = optionsArray;
1348
+ }
1349
+ fieldDefinition.editable = updateFieldForm.findField('updateEditable').getValue();
1350
+ fieldDefinition.forceSelection = updateFieldForm.findField('updateForceSelection').getValue();
1351
+ fieldDefinition.multiSelect = updateFieldForm.findField('updateMultiSelect').getValue();
1352
+ }
1353
+
1354
+ //console.log(fieldDefinition);
1355
+
1356
+ // use getIndexOfFieldByName and splice to replace field in definition to preserve field order
1357
+ var indexOfField = formBuilder.getIndexOfFieldByName(formPanel, formPanel.selected_field.name);
1358
+ //console.log(indexOfField);
1359
+
1360
+ formPanel.form_definition.splice(indexOfField, 1, fieldDefinition);
1361
+ //console.log(formPanel.form_definition);
1362
+
1363
+ // reload form from definition
1364
+ formBuilder.reloadForm(formPanel);
1365
+
1366
+ // re-highlight form item
1367
+ formPanel.getForm().findField(updateName).getEl().dom.click();
1368
+ }
1369
+ }
1370
+ }
1371
+ }
1372
+ ],
1373
+ defaults:{
1374
+ width: 230,
1375
+ labelWidth: 85
1376
+ },
1377
+ items:[]
1378
+ },
1379
+ {
1380
+ xtype: 'form',
1381
+ title: 'Form Properties',
1382
+ itemId: 'form_props',
1383
+ autoScroll: true,
1384
+ bodyPadding: 10,
1385
+ defaults:{
1386
+ width: 230,
1387
+ labelWidth: 85
1388
+ },
1389
+ items:[{
1390
+ fieldLabel: 'Form Title',
1391
+ name: 'description',
1392
+ xtype: 'textfield',
1393
+ allowBlank: false
1394
+ },
1395
+ {
1396
+ fieldLabel: 'Internal ID',
1397
+ name: 'internal_identifier',
1398
+ xtype: 'displayfield'
1399
+ },
1400
+ {
1401
+ fieldLabel: 'Widget Action',
1402
+ name: 'widget_action',
1403
+ xtype: 'combobox',
1404
+ width: 215,
1405
+ allowBlank: false,
1406
+ forceSelection:true,
1407
+ store: [
1408
+ ['email', 'Email Only'],
1409
+ ['save', 'Save Only'],
1410
+ ['both', 'Email & Save Data']
1411
+ ],
1412
+ listeners:{
1413
+ change:function(field, newValue, oldValue){
1414
+ var widget_email_recipients = field.findParentByType('form').getForm().findField('widget_email_recipients');
1415
+ widget_email_recipients.allowBlank = (field.getValue() == 'save');
1416
+ }
1417
+ },
1418
+ plugins: [new helpQtip("Configure the action to be taken when a form is submitted via Knitkit's Dynamic Forms Widget.<br /> Email Only will email but not save the data to the database.<br /> Save Only will save the data to the database but not email.<br /> Email & Save Data will do both.<br /> NOTE: The Contact Us Widget uses Knitkit's website configuration options for email behavior & not the Dynamic Forms Widget Action setting.")]
1419
+ },
1420
+ {
1421
+ fieldLabel: 'Email Recipients',
1422
+ name: 'widget_email_recipients',
1423
+ xtype: 'textfield',
1424
+ vtype: 'emailList',
1425
+ width: 215,
1426
+ listeners:{
1427
+ render:function(field){
1428
+ field.allowBlank = (field.findParentByType('form').getForm().findField('widget_action').getValue() == 'save');
1429
+ }
1430
+ },
1431
+ plugins: [new helpQtip('When Widget Action is set to Email only or Email & Save Data, this field is required. Enter a comma separated list of email addresses to receive data submitted with this form via the Knitkit Dynamic Forms widget.')]
1432
+ },
1433
+ {
1434
+ fieldLabel: 'Focus Field',
1435
+ name: 'focus_first_field',
1436
+ xtype: 'checkbox',
1437
+ width: 105,
1438
+ plugins: [new helpQtip('Do you want the cursor to autmatically focus the first form field? If there is text it will also automatically highlight.')]
1439
+ },
1440
+ {
1441
+ fieldLabel: 'Submit Button Label',
1442
+ name: 'submit_button_label',
1443
+ xtype: 'textfield',
1444
+ allowBlank: false
1445
+ },
1446
+ {
1447
+ fieldLabel: 'Cancel Button Label',
1448
+ name: 'cancel_button_label',
1449
+ xtype: 'textfield',
1450
+ allowBlank: false
1451
+ },
1452
+ {
1453
+ fieldLabel: 'Submit Empty Text',
1454
+ name: 'submit_empty_text',
1455
+ xtype: 'checkbox',
1456
+ width: 105,
1457
+ plugins: [new helpQtip('Empty Text is example text. Do you want to submit these example values if they are unchanged by the user?')]
1458
+ },
1459
+ {
1460
+ fieldLabel: 'Message Target',
1461
+ name: 'msg_target',
1462
+ xtype: 'combobox',
1463
+ allowBlank: false,
1464
+ editable: true,
1465
+ forceSelection:false,
1466
+ value: 'qtip',
1467
+ store: [
1468
+ ['qtip', 'Quick Tip'],
1469
+ ['side', 'Right of Field'],
1470
+ ['title', 'Title'],
1471
+ ['under', 'Under Field'],
1472
+ ['none', 'None']
1473
+ ]
1474
+ },
1475
+ {
1476
+ fieldLabel: 'Comment',
1477
+ labelAlign: 'top',
1478
+ name: 'comment',
1479
+ xtype: 'textarea'
1480
+ },
1481
+ {
1482
+ fieldLabel: 'Created At',
1483
+ name: 'created_at',
1484
+ xtype: 'displayfield'
1485
+ },
1486
+ {
1487
+ fieldLabel: 'Created By',
1488
+ name: 'created_by',
1489
+ xtype: 'displayfield'
1490
+ },
1491
+ {
1492
+ fieldLabel: 'Updated At',
1493
+ name: 'updated_at',
1494
+ xtype: 'displayfield'
1495
+ },
1496
+ {
1497
+ fieldLabel: 'Updated By',
1498
+ name: 'updated_by',
1499
+ xtype: 'displayfield'
1500
+ }
1501
+ ]
1502
+ }
1503
+ ]
85
1504
  }
86
- }]
1505
+ ]
1506
+
87
1507
  }, config);
88
1508
 
89
1509
  this.callParent([config]);
90
1510
  }
91
-
92
- });
93
-
1511
+ });