a029059f7d1c3fb0051b8c980610dce9529461eb
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Resources / Public / JavaScript / Wizard / Viewport / Left / Options / Forms / Validation / Rule.js
1 Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
2
3 /**
4 * The validation rules abstract
5 *
6 * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
7 * @extends Ext.FormPanel
8 */
9 TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule = Ext.extend(Ext.FormPanel, {
10 /**
11 * @cfg {Boolean} border
12 * True to display the borders of the panel's body element, false to hide
13 * them (defaults to true). By default, the border is a 2px wide inset
14 * border, but this can be further altered by setting bodyBorder to false.
15 */
16 border: false,
17
18 /**
19 * @cfg {Number/String} padding
20 * A shortcut for setting a padding style on the body element. The value can
21 * either be a number to be applied to all sides, or a normal css string
22 * describing padding.
23 */
24 padding: 0,
25
26 /**
27 * @cfg {String} defaultType
28 *
29 * The default xtype of child Components to create in this Container when
30 * a child item is specified as a raw configuration object,
31 * rather than as an instantiated Component.
32 *
33 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
34 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
35 */
36 defaultType: 'textfield',
37
38 /**
39 * @cfg {String} rule
40 *
41 * The name of this rule
42 */
43 rule: '',
44
45 /**
46 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
47 * regularly fires the clientvalidation event passing that state.
48 * When monitoring valid state, the FormPanel enables/disables any of its configured
49 * buttons which have been configured with formBind: true depending
50 * on whether the form is valid or not. Defaults to false
51 */
52 monitorValid: true,
53
54 /**
55 * Constructor
56 */
57 initComponent: function() {
58 var fields = this.getFieldsBySettings();
59 var formItems = new Array();
60
61 // Adds the specified events to the list of events which this Observable may fire.
62 this.addEvents({
63 'validation': true
64 });
65
66 Ext.iterate(fields, function(item, index, allItems) {
67 switch(item) {
68 case 'message':
69 formItems.push({
70 fieldLabel: TYPO3.l10n.localize('validation_properties_message'),
71 name: 'message',
72 allowBlank: false,
73 listeners: {
74 'triggerclick': {
75 scope: this,
76 fn: this.storeValue
77 }
78 }
79 });
80 break;
81 case 'error':
82 formItems.push({
83 fieldLabel: TYPO3.l10n.localize('validation_properties_error'),
84 name: 'error',
85 allowBlank: false,
86 listeners: {
87 'triggerclick': {
88 scope: this,
89 fn: this.storeValue
90 }
91 }
92 });
93 break;
94 case 'breakOnError':
95 formItems.push({
96 xtype: 'checkbox',
97 fieldLabel: TYPO3.l10n.localize('validation_properties_breakonerror'),
98 name: 'breakOnError',
99 inputValue: '1',
100 listeners: {
101 'check': {
102 scope: this,
103 fn: this.storeValue
104 }
105 }
106 });
107 break;
108 case 'showMessage':
109 formItems.push({
110 xtype: 'checkbox',
111 fieldLabel: TYPO3.l10n.localize('validation_properties_showmessage'),
112 name: 'showMessage',
113 inputValue: '1',
114 listeners: {
115 'check': {
116 scope: this,
117 fn: this.storeValue
118 }
119 }
120 });
121 break;
122 case 'allowWhiteSpace':
123 formItems.push({
124 xtype: 'checkbox',
125 fieldLabel: TYPO3.l10n.localize('validation_properties_allowwhitespace'),
126 name: 'allowWhiteSpace',
127 inputValue: '1',
128 listeners: {
129 'check': {
130 scope: this,
131 fn: this.storeValue
132 }
133 }
134 });
135 break;
136 case 'minimum':
137 formItems.push({
138 xtype: 'spinnerfield',
139 fieldLabel: TYPO3.l10n.localize('validation_properties_minimum'),
140 name: 'minimum',
141 minValue: 0,
142 accelerate: true,
143 listeners: {
144 'spin': {
145 scope: this,
146 fn: this.storeValue
147 }
148 }
149 });
150 break;
151 case 'maximum':
152 formItems.push({
153 xtype: 'spinnerfield',
154 fieldLabel: TYPO3.l10n.localize('validation_properties_maximum'),
155 name: 'maximum',
156 minValue: 0,
157 accelerate: true,
158 listeners: {
159 'spin': {
160 scope: this,
161 fn: this.storeValue
162 }
163 }
164 });
165 break;
166 case 'inclusive':
167 formItems.push({
168 xtype: 'checkbox',
169 fieldLabel: TYPO3.l10n.localize('validation_properties_inclusive'),
170 name: 'inclusive',
171 inputValue: '1',
172 listeners: {
173 'check': {
174 scope: this,
175 fn: this.storeValue
176 }
177 }
178 });
179 break;
180 case 'format':
181 formItems.push({
182 fieldLabel: TYPO3.l10n.localize('validation_properties_format'),
183 name: 'format',
184 allowBlank: false,
185 listeners: {
186 'triggerclick': {
187 scope: this,
188 fn: this.storeValue
189 }
190 }
191 });
192 break;
193 case 'field':
194 formItems.push({
195 fieldLabel: TYPO3.l10n.localize('validation_properties_field'),
196 name: 'field',
197 allowBlank: false,
198 listeners: {
199 'triggerclick': {
200 scope: this,
201 fn: this.storeValue
202 }
203 }
204 });
205 break;
206 case 'array':
207 formItems.push({
208 fieldLabel: TYPO3.l10n.localize('validation_properties_array'),
209 name: 'array',
210 allowBlank: false,
211 listeners: {
212 'triggerclick': {
213 scope: this,
214 fn: this.storeValue
215 }
216 }
217 });
218 break;
219 case 'expression':
220 formItems.push({
221 fieldLabel: TYPO3.l10n.localize('validation_properties_expression'),
222 name: 'expression',
223 allowBlank: false,
224 listeners: {
225 'triggerclick': {
226 scope: this,
227 fn: this.storeValue
228 }
229 }
230 });
231 case 'types':
232 formItems.push({
233 fieldLabel: TYPO3.l10n.localize('validation_properties_types'),
234 name: 'types',
235 allowBlank: false,
236 listeners: {
237 'triggerclick': {
238 scope: this,
239 fn: this.storeValue
240 }
241 }
242 });
243 break;
244 }
245 }, this);
246
247 formItems.push({
248 xtype: 'button',
249 text: TYPO3.l10n.localize('button_remove'),
250 handler: this.removeRule,
251 scope: this
252 });
253
254 var config = {
255 items: [
256 {
257 xtype: 'fieldset',
258 title: TYPO3.l10n.localize('validation_' + this.rule),
259 autoHeight: true,
260 defaults: {
261 width: 128,
262 msgTarget: 'side'
263 },
264 defaultType: 'textfieldsubmit',
265 items: formItems
266 }
267 ]
268 };
269
270 // apply config
271 Ext.apply(this, Ext.apply(this.initialConfig, config));
272
273 // call parent
274 TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule.superclass.initComponent.apply(this, arguments);
275
276 // Initialize clientvalidation event
277 this.on('clientvalidation', this.validation, this);
278
279 // Strange, but we need to call doLayout() after render
280 this.on('afterrender', this.newOrExistingRule, this);
281 },
282
283 /**
284 * Decide whether this is a new or an existing one
285 *
286 * If new, the default configuration has to be added to the validation rules
287 * of the element, otherwise we can fill the form with the existing configuration
288 */
289 newOrExistingRule: function() {
290 this.doLayout();
291 // Existing rule
292 if (this.element.configuration.validation[this.rule]) {
293 this.fillForm();
294 // New rule
295 } else {
296 this.addRuleToElement();
297 }
298 },
299
300 /**
301 * Fill the form with the configuration of the element
302 *
303 * When filling, the events of all form elements should be suspended,
304 * otherwise the values are written back to the element, for instance on a
305 * check event on a checkbox.
306 */
307 fillForm: function() {
308 this.suspendEventsBeforeFilling();
309 this.getForm().setValues(this.element.configuration.validation[this.rule]);
310 this.resumeEventsAfterFilling();
311 },
312
313 /**
314 * Suspend the events on all items within this component
315 */
316 suspendEventsBeforeFilling: function() {
317 this.cascade(function(item) {
318 item.suspendEvents();
319 });
320 },
321
322 /**
323 * Resume the events on all items within this component
324 */
325 resumeEventsAfterFilling: function() {
326 this.cascade(function(item) {
327 item.resumeEvents();
328 });
329 },
330
331 /**
332 * Add this rule to the element
333 */
334 addRuleToElement: function() {
335 var formConfiguration = {validation: {}};
336 formConfiguration.validation[this.rule] = this.configuration;
337
338 this.element.setConfigurationValue(formConfiguration);
339
340 this.fillForm();
341 },
342
343 /**
344 * Store a changed value from the form in the element
345 *
346 * @param {Object} field The field which has changed
347 */
348 storeValue: function(field) {
349 if (field.isValid()) {
350 var fieldName = field.getName();
351
352 var formConfiguration = {validation: {}};
353 formConfiguration.validation[this.rule] = {};
354 formConfiguration.validation[this.rule][fieldName] = field.getValue();
355
356 this.element.setConfigurationValue(formConfiguration);
357 }
358 },
359
360 /**
361 * Remove the rule
362 *
363 * Called when the remove button of this rule has been clicked
364 */
365 removeRule: function() {
366 this.ownerCt.removeRule(this);
367 this.element.removeValidationRule(this.rule);
368 },
369
370 /**
371 * Get the fields for the element
372 *
373 * Based on the TSconfig general allowed fields
374 * and the TSconfig allowed fields for this type of element
375 *
376 * @returns object
377 */
378 getFieldsBySettings: function() {
379 var fields = [];
380 var ruleFields = this.configuration;
381 var elementType = this.element.xtype.split('-').pop();
382
383 var allowedGeneralFields = [];
384 try {
385 allowedGeneralFields = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.validation.rules[this.rule].showProperties.split(/[, ]+/);
386 } catch (error) {
387 // The object has not been found or constructed wrong
388 allowedGeneralFields = [
389 'message',
390 'error',
391 'breakOnError',
392 'showMessage',
393 'allowWhiteSpace',
394 'minimum',
395 'maximum',
396 'inclusive',
397 'format',
398 'field',
399 'array',
400 'strict',
401 'expression'
402 ];
403 }
404
405 var allowedElementFields = [];
406 try {
407 allowedElementFields = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.validation.rules[this.rule].showProperties.split(/[, ]+/);
408 } catch (error) {
409 // The object has not been found or constructed wrong
410 allowedElementFields = allowedGeneralFields;
411 }
412
413 Ext.iterate(allowedElementFields, function(item, index, allItems) {
414 if (allowedGeneralFields.indexOf(item) > -1 && Ext.isDefined(ruleFields[item])) {
415 fields.push(item);
416 }
417 }, this);
418
419 return fields;
420 },
421
422 /**
423 * Called by the clientvalidation event
424 *
425 * Adds or removes the error class if the form is valid or not
426 *
427 * @param {Object} formPanel This formpanel
428 * @param {Boolean} valid True if the client validation is true
429 */
430 validation: function(formPanel, valid) {
431 if (this.el) {
432 if (valid && this.el.hasClass('validation-error')) {
433 this.removeClass('validation-error');
434 this.fireEvent('validation', this.rule, valid);
435 } else if (!valid && !this.el.hasClass('validation-error')) {
436 this.addClass('validation-error');
437 this.fireEvent('validation', this.rule, valid);
438 }
439 }
440 }
441 });
442
443 Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-rule', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule);