1
|
|
|
<?php namespace XoopsModules\Smartobject\Form; |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Contains the class responsible for providing forms related to a SmartObject |
5
|
|
|
* |
6
|
|
|
* @license GNU |
7
|
|
|
* @author marcan <[email protected]> |
8
|
|
|
* @link http://smartfactory.ca The SmartFactory |
9
|
|
|
* @package SmartObject |
10
|
|
|
* @subpackage SmartObjectForm |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
use XoopsModules\Smartobject; |
14
|
|
|
/** @var Smartobject\Helper $helper */ |
15
|
|
|
$helper = Smartobject\Helper::getInstance(); |
16
|
|
|
|
17
|
|
|
// defined('XOOPS_ROOT_PATH') || die('Restricted access'); |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Including the XoopsFormLoader classes |
21
|
|
|
*/ |
22
|
|
|
use XoopsFormDhtmlTextArea; |
23
|
|
|
use XoopsFormEditor; |
24
|
|
|
use XoopsFormElement; |
25
|
|
|
use XoopsFormTextArea; |
26
|
|
|
use XoopsModules\Smartobject\Form\Elements\SmartFormCheckElement; |
27
|
|
|
use XoopsModules\Smartobject\Form\Elements\SmartFormRichFileElement; |
28
|
|
|
use XoopsModules\Smartobject\Form\Elements\SmartFormSection; |
29
|
|
|
use XoopsModules\Smartobject\Form\Elements\SmartFormSectionClose; |
30
|
|
|
use XoopsModules\Smartobject\Form\Elements\SmartFormUrlLinkElement; |
31
|
|
|
|
32
|
|
|
require_once XOOPS_ROOT_PATH . '/class/xoopsformloader.php'; |
33
|
|
|
//require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/smartformsection.php'; |
34
|
|
|
//require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/smartformsectionclose.php'; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* SmartForm base class |
38
|
|
|
* |
39
|
|
|
* Base class representing a single form for a specific SmartObject |
40
|
|
|
* |
41
|
|
|
* @package SmartObject |
42
|
|
|
* @author marcan <[email protected]> |
43
|
|
|
* @link http://smartfactory.ca The SmartFactory |
44
|
|
|
*/ |
45
|
|
|
class SmartObjectForm extends \XoopsThemeForm |
46
|
|
|
{ |
47
|
|
|
public $targetObject = null; |
48
|
|
|
public $form_fields = null; |
49
|
|
|
public $_cancel_js_action = false; |
50
|
|
|
public $_custom_button = false; |
51
|
|
|
public $_captcha = false; |
52
|
|
|
public $_form_name = false; |
53
|
|
|
public $_form_caption = false; |
54
|
|
|
public $_submit_button_caption = false; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* SmartobjectForm constructor. |
58
|
|
|
* @param string $target |
59
|
|
|
* @param string $form_name |
60
|
|
|
* @param string $form_caption |
61
|
|
|
* @param string $form_action |
62
|
|
|
* @param null $form_fields |
63
|
|
|
* @param bool $submit_button_caption |
64
|
|
|
* @param bool $cancel_js_action |
65
|
|
|
* @param bool $captcha |
66
|
|
|
*/ |
67
|
|
|
public function __construct( |
68
|
|
|
&$target, |
69
|
|
|
$form_name, |
70
|
|
|
$form_caption, |
71
|
|
|
$form_action, |
72
|
|
|
$form_fields = null, |
73
|
|
|
$submit_button_caption = false, |
74
|
|
|
$cancel_js_action = false, |
75
|
|
|
$captcha = false |
76
|
|
|
) { |
77
|
|
|
$this->targetObject =& $target; |
78
|
|
|
$this->form_fields = $form_fields; |
79
|
|
|
$this->_cancel_js_action = $cancel_js_action; |
80
|
|
|
$this->_captcha = $captcha; |
81
|
|
|
$this->_form_name = $form_name; |
|
|
|
|
82
|
|
|
$this->_form_caption = $form_caption; |
|
|
|
|
83
|
|
|
$this->_submit_button_caption = $submit_button_caption; |
84
|
|
|
|
85
|
|
|
if (!isset($form_action)) { |
86
|
|
|
$form_action = xoops_getenv('PHP_SELF'); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
parent::__construct($form_caption, $form_name, $form_action, 'post', true); |
90
|
|
|
$this->setExtra('enctype="multipart/form-data"'); |
91
|
|
|
|
92
|
|
|
$this->createElements(); |
93
|
|
|
|
94
|
|
|
if ($captcha) { |
95
|
|
|
$this->addCaptcha(); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
$this->createPermissionControls(); |
99
|
|
|
|
100
|
|
|
$this->createButtons($form_name, $form_caption, $submit_button_caption); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
public function addCaptcha() |
104
|
|
|
{ |
105
|
|
|
require_once SMARTOBJECT_ROOT_PATH . 'include/captcha/formcaptcha.php'; |
106
|
|
|
$this->addElement(new \XoopsFormCaptcha(), true); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* @param $name |
111
|
|
|
* @param $caption |
112
|
|
|
* @param bool $onclick |
113
|
|
|
*/ |
114
|
|
|
public function addCustomButton($name, $caption, $onclick = false) |
115
|
|
|
{ |
116
|
|
|
$custom_button_array = [ |
117
|
|
|
'name' => $name, |
118
|
|
|
'caption' => $caption, |
119
|
|
|
'onclick' => $onclick |
120
|
|
|
]; |
121
|
|
|
$this->_custom_button[] = $custom_button_array; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Add an element to the form |
126
|
|
|
* |
127
|
|
|
* @param string|XoopsFormElement &$formElement reference to a {@link XoopsFormElement} |
128
|
|
|
* @param bool $key |
129
|
|
|
* @param bool $var |
130
|
|
|
* @param bool|string $required is this a "required" element? |
131
|
|
|
*/ |
132
|
|
|
public function addElement($formElement, $key = false, $var = false, $required = 'notset') |
133
|
|
|
{ |
134
|
|
|
if ($key) { |
135
|
|
|
if ($this->targetObject->vars[$key]['readonly']) { |
136
|
|
|
$formElement->setExtra('disabled="disabled"'); |
137
|
|
|
$formElement->setName($key . '-readonly'); |
138
|
|
|
// Since this element is disable, we still want to pass it's value in the form |
139
|
|
|
$hidden = new \XoopsFormHidden($key, $this->targetObject->vars[$key]['value']); |
140
|
|
|
$this->addElement($hidden); |
141
|
|
|
} |
142
|
|
|
$formElement->setDescription($var['form_dsc']); |
143
|
|
|
if (isset($this->targetObject->controls[$key]['onSelect'])) { |
144
|
|
|
$hidden = new \XoopsFormHidden('changedField', false); |
145
|
|
|
$this->addElement($hidden); |
146
|
|
|
$otherExtra = isset($var['form_extra']) ? $var['form_extra'] : ''; |
147
|
|
|
$onchangedString = "this.form.elements.changedField.value='$key'; this.form.elements.op.value='changedField'; submit()"; |
148
|
|
|
$formElement->setExtra('onchange="' . $onchangedString . '"' . ' ' . $otherExtra); |
149
|
|
|
} else { |
150
|
|
|
if (isset($var['form_extra'])) { |
151
|
|
|
$formElement->setExtra($var['form_extra']); |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
$controls = $this->targetObject->controls; |
155
|
|
|
if (isset($controls[$key]['js'])) { |
156
|
|
|
$formElement->customValidationCode[] = $controls[$key]['js']; |
157
|
|
|
} |
158
|
|
|
parent::addElement($formElement, 'notset' === $required ? $var['required'] : $required); |
159
|
|
|
} else { |
160
|
|
|
parent::addElement($formElement, 'notset' === $required ? false : true); |
161
|
|
|
} |
162
|
|
|
unset($formElement); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
public function createElements() |
166
|
|
|
{ |
167
|
|
|
$controls = $this->targetObject->controls; |
168
|
|
|
$vars = $this->targetObject->vars; |
169
|
|
|
foreach ($vars as $key => $var) { |
170
|
|
|
|
171
|
|
|
// If $displayOnForm is false OR this is the primary key, it doesn't |
172
|
|
|
// need to be displayed, then we only create an hidden field |
173
|
|
|
if ($key == $this->targetObject->handler->keyName || !$var['displayOnForm']) { |
174
|
|
|
$elementToAdd = new \XoopsFormHidden($key, $var['value']); |
175
|
|
|
$this->addElement($elementToAdd, $key, $var, false); |
176
|
|
|
unset($elementToAdd); |
177
|
|
|
// If not, the we need to create the proper form control for this fields |
178
|
|
|
} else { |
179
|
|
|
// If this field has a specific control, we will use it |
180
|
|
|
|
181
|
|
|
if ('parentid' === $key) { |
182
|
|
|
/** |
183
|
|
|
* Why this ? |
184
|
|
|
*/ |
185
|
|
|
} |
186
|
|
|
if (isset($controls[$key])) { |
187
|
|
|
/* If the control has name, it's because it's an object already present in the script |
188
|
|
|
* for example, "user" |
189
|
|
|
* If the field does not have a name, than we will use a "select" (ie XoopsFormSelect) |
190
|
|
|
*/ |
191
|
|
|
if (!isset($controls[$key]['name']) || !$controls[$key]['name']) { |
192
|
|
|
$controls[$key]['name'] = 'select'; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
$form_select = $this->getControl($controls[$key]['name'], $key); |
196
|
|
|
|
197
|
|
|
// Adding on the form, the control for this field |
198
|
|
|
$this->addElement($form_select, $key, $var); |
199
|
|
|
unset($form_select); |
200
|
|
|
|
201
|
|
|
// If this field don't have a specific control, we will use the standard one, depending on its data type |
202
|
|
|
} else { |
203
|
|
|
switch ($var['data_type']) { |
204
|
|
|
|
205
|
|
|
case XOBJ_DTYPE_TXTBOX: |
206
|
|
|
|
207
|
|
|
$form_text = $this->getControl('text', $key); |
208
|
|
|
$this->addElement($form_text, $key, $var); |
209
|
|
|
unset($form_text); |
210
|
|
|
break; |
211
|
|
|
|
212
|
|
View Code Duplication |
case XOBJ_DTYPE_INT: |
|
|
|
|
213
|
|
|
$this->targetObject->setControl($key, [ |
|
|
|
|
214
|
|
|
'name' => 'text', |
215
|
|
|
'size' => '5' |
216
|
|
|
]); |
217
|
|
|
$form_text = $this->getControl('text', $key); |
218
|
|
|
$this->addElement($form_text, $key, $var); |
219
|
|
|
unset($form_text); |
220
|
|
|
break; |
221
|
|
|
|
222
|
|
View Code Duplication |
case XOBJ_DTYPE_FLOAT: |
|
|
|
|
223
|
|
|
$this->targetObject->setControl($key, [ |
|
|
|
|
224
|
|
|
'name' => 'text', |
225
|
|
|
'size' => '5' |
226
|
|
|
]); |
227
|
|
|
$form_text = $this->getControl('text', $key); |
228
|
|
|
$this->addElement($form_text, $key, $var); |
229
|
|
|
unset($form_text); |
230
|
|
|
break; |
231
|
|
|
|
232
|
|
|
case XOBJ_DTYPE_LTIME: |
233
|
|
|
$form_date_time = $this->getControl('date_time', $key); |
234
|
|
|
$this->addElement($form_date_time, $key, $var); |
235
|
|
|
unset($form_date_time); |
236
|
|
|
break; |
237
|
|
|
|
238
|
|
|
case XOBJ_DTYPE_STIME: |
239
|
|
|
$form_date_time = $this->getControl('date', $key); |
240
|
|
|
$this->addElement($form_date_time, $key, $var); |
241
|
|
|
unset($form_date_time); |
242
|
|
|
break; |
243
|
|
|
|
244
|
|
|
case XOBJ_DTYPE_TIME_ONLY: |
245
|
|
|
$form_time = $this->getControl('time', $key); |
246
|
|
|
$this->addElement($form_time, $key, $var); |
247
|
|
|
unset($form_time); |
248
|
|
|
break; |
249
|
|
|
|
250
|
|
View Code Duplication |
case XOBJ_DTYPE_CURRENCY: |
|
|
|
|
251
|
|
|
$this->targetObject->setControl($key, [ |
|
|
|
|
252
|
|
|
'name' => 'text', |
253
|
|
|
'size' => '15' |
254
|
|
|
]); |
255
|
|
|
$form_currency = $this->getControl('text', $key); |
256
|
|
|
$this->addElement($form_currency, $key, $var); |
257
|
|
|
unset($form_currency); |
258
|
|
|
break; |
259
|
|
|
|
260
|
|
|
case XOBJ_DTYPE_URLLINK: |
261
|
|
|
$form_urllink = $this->getControl('urllink', $key); |
262
|
|
|
$this->addElement($form_urllink, $key, $var); |
263
|
|
|
unset($form_urllink); |
264
|
|
|
break; |
265
|
|
|
|
266
|
|
|
case XOBJ_DTYPE_FILE: |
267
|
|
|
$form_file = $this->getControl('richfile', $key); |
268
|
|
|
$this->addElement($form_file, $key, $var); |
269
|
|
|
unset($form_file); |
270
|
|
|
break; |
271
|
|
|
|
272
|
|
|
case XOBJ_DTYPE_TXTAREA: |
273
|
|
|
|
274
|
|
|
$form_text_area = $this->getTextArea($key, $var); |
275
|
|
|
$this->addElement($form_text_area, $key, $var); |
276
|
|
|
unset($form_text_area); |
277
|
|
|
break; |
278
|
|
|
|
279
|
|
|
case XOBJ_DTYPE_ARRAY: |
280
|
|
|
// TODO: To come... |
281
|
|
|
break; |
282
|
|
|
case XOBJ_DTYPE_SOURCE: |
283
|
|
|
// TODO: To come... |
284
|
|
|
break; |
285
|
|
|
case XOBJ_DTYPE_FORM_SECTION: |
286
|
|
|
$section_control = new SmartFormSection($key, $var['value']); |
287
|
|
|
$this->addElement($section_control, $key, $var); |
288
|
|
|
unset($section_control); |
289
|
|
|
break; |
290
|
|
|
case XOBJ_DTYPE_FORM_SECTION_CLOSE: |
291
|
|
|
$section_control = new SmartFormSectionClose($key, $var['value']); |
292
|
|
|
$this->addElement($section_control, $key, $var); |
293
|
|
|
unset($section_control); |
294
|
|
|
break; |
295
|
|
|
} |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
// Add an hidden field to store the URL of the page before this form |
300
|
|
|
$this->addElement(new \XoopsFormHidden('smart_page_before_form', Smartobject\Utility::getPageBeforeForm())); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
public function createPermissionControls() |
304
|
|
|
{ |
305
|
|
|
$smartModuleConfig = $this->targetObject->handler->getModuleConfig(); |
306
|
|
|
|
307
|
|
|
$permissions = $this->targetObject->handler->getPermissions(); |
308
|
|
|
|
309
|
|
|
if ($permissions) { |
310
|
|
|
$memberHandler = xoops_getHandler('member'); |
311
|
|
|
$group_list = $memberHandler->getGroupList(); |
312
|
|
|
asort($group_list); |
313
|
|
|
foreach ($permissions as $permission) { |
314
|
|
|
if ($this->targetObject->isNew()) { |
|
|
|
|
315
|
|
|
if (isset($smartModuleConfig['def_perm_' . $permission['perm_name']])) { |
316
|
|
|
$groups_value = $smartModuleConfig['def_perm_' . $permission['perm_name']]; |
317
|
|
|
} |
318
|
|
|
} else { |
319
|
|
|
$groups_value = $this->targetObject->getGroupPerm($permission['perm_name']); |
|
|
|
|
320
|
|
|
} |
321
|
|
|
$groups_select = new \XoopsFormSelect($permission['caption'], $permission['perm_name'], $groups_value, 4, true); |
|
|
|
|
322
|
|
|
$groups_select->setDescription($permission['description']); |
323
|
|
|
$groups_select->addOptionArray($group_list); |
324
|
|
|
$this->addElement($groups_select); |
325
|
|
|
unset($groups_select); |
326
|
|
|
} |
327
|
|
|
} |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* @param $form_name |
332
|
|
|
* @param $form_caption |
333
|
|
|
* @param bool $submit_button_caption |
334
|
|
|
*/ |
335
|
|
|
public function createButtons($form_name, $form_caption, $submit_button_caption = false) |
336
|
|
|
{ |
337
|
|
|
$button_tray = new \XoopsFormElementTray('', ''); |
338
|
|
|
$button_tray->addElement(new \XoopsFormHidden('op', $form_name)); |
339
|
|
|
if (!$submit_button_caption) { |
340
|
|
|
if ($this->targetObject->isNew()) { |
|
|
|
|
341
|
|
|
$butt_create = new \XoopsFormButton('', 'create_button', _CO_SOBJECT_CREATE, 'submit'); |
342
|
|
|
} else { |
343
|
|
|
$butt_create = new \XoopsFormButton('', 'modify_button', _CO_SOBJECT_MODIFY, 'submit'); |
344
|
|
|
} |
345
|
|
|
} else { |
346
|
|
|
$butt_create = new \XoopsFormButton('', 'modify_button', $submit_button_caption, 'submit'); |
347
|
|
|
} |
348
|
|
|
$butt_create->setExtra('onclick="this.form.elements.op.value=\'' . $form_name . '\'"'); |
349
|
|
|
$button_tray->addElement($butt_create); |
350
|
|
|
|
351
|
|
|
//creating custom buttons |
352
|
|
|
if ($this->_custom_button) { |
353
|
|
|
foreach ($this->_custom_button as $custom_button) { |
|
|
|
|
354
|
|
|
$butt_custom = new \XoopsFormButton('', $custom_button['name'], $custom_button['caption'], 'submit'); |
355
|
|
|
if ($custom_button['onclick']) { |
356
|
|
|
$butt_custom->setExtra('onclick="' . $custom_button['onclick'] . '"'); |
357
|
|
|
} |
358
|
|
|
$button_tray->addElement($butt_custom); |
359
|
|
|
unset($butt_custom); |
360
|
|
|
} |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
// creating the "cancel" button |
364
|
|
|
$butt_cancel = new \XoopsFormButton('', 'cancel_button', _CO_SOBJECT_CANCEL, 'button'); |
365
|
|
|
if ($this->_cancel_js_action) { |
366
|
|
|
$butt_cancel->setExtra('onclick="' . $this->_cancel_js_action . '"'); |
367
|
|
|
} else { |
368
|
|
|
$butt_cancel->setExtra('onclick="history.go(-1)"'); |
369
|
|
|
} |
370
|
|
|
$button_tray->addElement($butt_cancel); |
371
|
|
|
|
372
|
|
|
$this->addElement($button_tray); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* @param $controlName |
377
|
|
|
* @param $key |
378
|
|
|
* @return \XoopsFormLabel |
379
|
|
|
*/ |
380
|
|
|
public function getControl($controlName, $key) |
381
|
|
|
{ |
382
|
|
|
switch ($controlName) { |
383
|
|
View Code Duplication |
case 'check': |
|
|
|
|
384
|
|
|
// require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/smartformcheckelement.php'; |
385
|
|
|
$control = $this->targetObject->getControl($key); |
|
|
|
|
386
|
|
|
$controlObj = new SmartFormCheckElement($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getVar($key)); |
|
|
|
|
387
|
|
|
$controlObj->addOptionArray($control['options']); |
388
|
|
|
|
389
|
|
|
return $controlObj; |
390
|
|
|
break; |
|
|
|
|
391
|
|
|
|
392
|
|
|
case 'color': |
393
|
|
|
$control = $this->targetObject->getControl($key); |
|
|
|
|
394
|
|
|
$controlObj = new \XoopsFormColorPicker($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getVar($key)); |
|
|
|
|
395
|
|
|
|
396
|
|
|
return $controlObj; |
|
|
|
|
397
|
|
|
break; |
|
|
|
|
398
|
|
|
|
399
|
|
View Code Duplication |
case 'radio': |
|
|
|
|
400
|
|
|
$control = $this->targetObject->getControl($key); |
|
|
|
|
401
|
|
|
|
402
|
|
|
$controlObj = new \XoopsFormRadio($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getVar($key)); |
|
|
|
|
403
|
|
|
$controlObj->addOptionArray($control['options']); |
404
|
|
|
|
405
|
|
|
return $controlObj; |
|
|
|
|
406
|
|
|
break; |
|
|
|
|
407
|
|
|
|
408
|
|
|
case 'label': |
409
|
|
|
return new \XoopsFormLabel($this->targetObject->vars[$key]['form_caption'], $this->targetObject->getVar($key)); |
|
|
|
|
410
|
|
|
break; |
|
|
|
|
411
|
|
|
|
412
|
|
|
case 'textarea': |
413
|
|
|
return $this->getTextArea($key); |
|
|
|
|
414
|
|
|
|
415
|
|
|
case 'theme': |
416
|
|
|
return $this->getThemeSelect($key, $this->targetObject->vars[$key]); |
|
|
|
|
417
|
|
|
|
418
|
|
|
case 'theme_multi': |
419
|
|
|
return $this->getThemeSelect($key, $this->targetObject->vars[$key], true); |
|
|
|
|
420
|
|
|
break; |
|
|
|
|
421
|
|
|
|
422
|
|
|
case 'timezone': |
423
|
|
|
return new \XoopsFormSelectTimezone($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getVar($key)); |
|
|
|
|
424
|
|
|
break; |
|
|
|
|
425
|
|
|
|
426
|
|
View Code Duplication |
case 'group': |
|
|
|
|
427
|
|
|
return new \XoopsFormSelectGroup($this->targetObject->vars[$key]['form_caption'], $key, false, $this->targetObject->getVar($key, 'e'), 1, false); |
|
|
|
|
428
|
|
|
break; |
|
|
|
|
429
|
|
|
|
430
|
|
View Code Duplication |
case 'group_multi': |
|
|
|
|
431
|
|
|
return new \XoopsFormSelectGroup($this->targetObject->vars[$key]['form_caption'], $key, false, $this->targetObject->getVar($key, 'e'), 5, true); |
|
|
|
|
432
|
|
|
break; |
|
|
|
|
433
|
|
|
|
434
|
|
|
/*case 'user': |
435
|
|
|
return new \XoopsFormSelectUser($this->targetObject->vars[$key]['form_caption'], $key, false, $this->targetObject->getVar($key, 'e'), 1, false); |
436
|
|
|
break;*/ |
437
|
|
|
|
438
|
|
View Code Duplication |
case 'user_multi': |
|
|
|
|
439
|
|
|
return new \XoopsFormSelectUser($this->targetObject->vars[$key]['form_caption'], $key, false, $this->targetObject->getVar($key, 'e'), 5, true); |
|
|
|
|
440
|
|
|
break; |
|
|
|
|
441
|
|
|
|
442
|
|
View Code Duplication |
case 'password': |
|
|
|
|
443
|
|
|
return new \XoopsFormPassword($this->targetObject->vars[$key]['form_caption'], $key, 50, 255, $this->targetObject->getVar($key, 'e')); |
|
|
|
|
444
|
|
|
break; |
|
|
|
|
445
|
|
|
|
446
|
|
|
case 'country': |
447
|
|
|
return new \XoopsFormSelectCountry($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getVar($key, 'e')); |
|
|
|
|
448
|
|
|
break; |
|
|
|
|
449
|
|
|
|
450
|
|
|
case 'urllink': |
451
|
|
|
// require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/smartformurllinkelement.php'; |
452
|
|
|
|
453
|
|
|
return new SmartFormUrlLinkElement($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getUrlLinkObj($key)); |
|
|
|
|
454
|
|
|
break; |
|
|
|
|
455
|
|
|
|
456
|
|
|
case 'richfile': |
457
|
|
|
// require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/smartformrichfileelement.php'; |
458
|
|
|
|
459
|
|
|
return new SmartFormRichFileElement($this->targetObject->vars[$key]['form_caption'], $key, $this->targetObject->getFileObj($key)); |
|
|
|
|
460
|
|
|
break; |
|
|
|
|
461
|
|
|
case 'section': |
462
|
|
|
// require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/smartformsection.php'; |
463
|
|
|
|
464
|
|
|
return new SmartFormSection($key, $this->targetObject->vars[$key]['form_caption']); |
465
|
|
|
break; |
|
|
|
|
466
|
|
|
|
467
|
|
|
default: |
468
|
|
|
$classname = 'SmartForm' . ucfirst($controlName) . 'Element'; |
469
|
|
|
if (!class_exists($classname)) { |
470
|
|
|
if (file_exists(SMARTOBJECT_ROOT_PATH . 'class/form/elements/' . strtolower($classname) . '.php')) { |
471
|
|
|
// require_once SMARTOBJECT_ROOT_PATH . 'class/form/elements/' . strtolower($classname) . '.php'; |
472
|
|
|
} else { |
473
|
|
|
// perhaps this is a control created by the module |
474
|
|
|
$moduleName = $this->targetObject->handler->_moduleName; |
475
|
|
|
$moduleFormElementsPath = $this->targetObject->handler->_modulePath . 'class/form/elements/'; |
476
|
|
|
$classname = ucfirst($moduleName) . ucfirst($controlName) . 'Element'; |
477
|
|
|
$classFileName = strtolower($classname) . '.php'; |
478
|
|
|
|
479
|
|
|
if (file_exists($moduleFormElementsPath . $classFileName)) { |
480
|
|
|
// require_once $moduleFormElementsPath . $classFileName; |
481
|
|
|
} else { |
482
|
|
|
trigger_error($classname . ' Not found', E_USER_WARNING); |
483
|
|
|
|
484
|
|
|
return new \XoopsFormLabel(); //Empty object |
485
|
|
|
} |
486
|
|
|
} |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
return new $classname($this->targetObject, $key); |
490
|
|
|
break; |
|
|
|
|
491
|
|
|
} |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* @param $key |
496
|
|
|
* @return \XoopsFormDhtmlTextArea|\XoopsFormEditor|\XoopsFormTextArea|\XoopsFormTinymce|\XoopsFormTinymce4 |
497
|
|
|
*/ |
498
|
|
|
public function getTextArea($key) |
499
|
|
|
{ |
500
|
|
|
$var = $this->targetObject->vars[$key]; |
501
|
|
|
|
502
|
|
|
// if no control has been created, let's create a default one |
503
|
|
|
if (!isset($this->targetObject->controls[$key])) { |
504
|
|
|
$control = [ |
505
|
|
|
'name' => 'textarea', |
506
|
|
|
'itemHandler' => false, |
507
|
|
|
'method' => false, |
508
|
|
|
'module' => false, |
509
|
|
|
'form_editor' => 'default' |
510
|
|
|
]; |
511
|
|
|
} else { |
512
|
|
|
$control = $this->targetObject->controls[$key]; |
513
|
|
|
} |
514
|
|
|
$xoops22 = Smartobject\Utility::isXoops22(); |
515
|
|
|
|
516
|
|
|
$form_editor = isset($control['form_editor']) ? $control['form_editor'] : 'textarea'; |
517
|
|
|
/** |
518
|
|
|
* If the editor is 'default', retreive the default editor of this module |
519
|
|
|
*/ |
520
|
|
View Code Duplication |
if ('default' === $form_editor) { |
|
|
|
|
521
|
|
|
/** @var Smartobject\Helper $helper */ |
522
|
|
|
$helper = Smartobject\Helper::getInstance(); |
523
|
|
|
$form_editor = null !== ($helper->getConfig('default_editor')) ? $helper->getConfig('default_editor') : 'textarea'; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
$caption = $var['form_caption']; |
527
|
|
|
$name = $key; |
528
|
|
|
|
529
|
|
|
$value = $this->targetObject->getVar($key); |
|
|
|
|
530
|
|
|
|
531
|
|
|
$value = $this->targetObject->getValueFor($key, true); |
|
|
|
|
532
|
|
|
|
533
|
|
|
$editor_configs = []; |
534
|
|
|
$editor_configs['name'] = $name; |
535
|
|
|
$editor_configs['value'] = $value; |
536
|
|
|
if ('textarea' !== $form_editor) { |
537
|
|
|
$editor_configs['rows'] = 35; |
538
|
|
|
$editor_configs['cols'] = 60; |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
if (isset($control['rows'])) { |
542
|
|
|
$editor_configs['rows'] = $control['rows']; |
543
|
|
|
} |
544
|
|
|
if (isset($control['cols'])) { |
545
|
|
|
$editor_configs['cols'] = $control['cols']; |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
$editor_configs['width'] = '100%'; |
549
|
|
|
$editor_configs['height'] = '400px'; |
550
|
|
|
|
551
|
|
|
$dhtml = true; |
552
|
|
|
$xoopseditorclass = XOOPS_ROOT_PATH . '/class/xoopsform/formeditor.php'; |
553
|
|
|
|
554
|
|
|
if (file_exists($xoopseditorclass)) { |
555
|
|
|
require_once $xoopseditorclass; |
556
|
|
|
$editor = new \XoopsFormEditor($caption, $form_editor, $editor_configs, $nohtml = false, $onfailure = 'textarea'); |
557
|
|
|
} else { |
558
|
|
|
switch ($form_editor) { |
559
|
|
|
|
560
|
|
|
case 'tiny': |
561
|
|
|
if (!$xoops22) { |
562
|
|
|
if (is_readable(XOOPS_ROOT_PATH . '/class/xoopseditor/tinyeditor/formtinytextarea.php')) { |
563
|
|
|
require_once XOOPS_ROOT_PATH . '/class/xoopseditor/tinyeditor/formtinytextarea.php'; |
564
|
|
|
$editor = new \XoopsFormTinymce([ |
565
|
|
|
'caption' => $caption, |
566
|
|
|
'name' => $name, |
567
|
|
|
'value' => $value, |
568
|
|
|
'width' => '100%', |
569
|
|
|
'height' => '300px' |
570
|
|
|
], true); |
571
|
|
|
} else { |
572
|
|
|
if ($dhtml) { |
573
|
|
|
$editor = new \XoopsFormDhtmlTextArea($caption, $name, $value, 20, 60); |
574
|
|
|
} else { |
575
|
|
|
$editor = new \XoopsFormTextArea($caption, $name, $value, 7, 60); |
576
|
|
|
} |
577
|
|
|
} |
578
|
|
|
} else { |
579
|
|
|
$editor = new \XoopsFormEditor($caption, 'tinyeditor', $editor_configs); |
580
|
|
|
} |
581
|
|
|
break; |
582
|
|
|
|
583
|
|
|
case 'dhtmltextarea': |
584
|
|
|
case 'dhtmltext': |
585
|
|
|
$editor = new \XoopsFormDhtmlTextArea($var['form_caption'], $key, $this->targetObject->getVar($key, 'e'), 20, 60); |
|
|
|
|
586
|
|
|
if ($var['form_dsc']) { |
587
|
|
|
$editor->setDescription($var['form_dsc']); |
588
|
|
|
} |
589
|
|
|
break; |
590
|
|
|
|
591
|
|
|
// case 'inbetween': |
592
|
|
|
// if (!$xoops22) { |
593
|
|
|
// if (is_readable(XOOPS_ROOT_PATH . '/class/xoopseditor/inbetween/forminbetweentextarea.php')) { |
594
|
|
|
// require_once XOOPS_ROOT_PATH . '/class/xoopseditor/inbetween/forminbetweentextarea.php'; |
595
|
|
|
// $editor = new \XoopsFormInbetweenTextArea([ |
596
|
|
|
// 'caption' => $caption, |
597
|
|
|
// 'name' => $name, |
598
|
|
|
// 'value' => $value, |
599
|
|
|
// 'width' => '100%', |
600
|
|
|
// 'height' => '300px' |
601
|
|
|
// ], true); |
602
|
|
|
// } else { |
603
|
|
|
// if ($dhtml) { |
604
|
|
|
// $editor = new \XoopsFormDhtmlTextArea($caption, $name, $value, 20, 60); |
605
|
|
|
// } else { |
606
|
|
|
// $editor = new \XoopsFormTextArea($caption, $name, $value, 7, 60); |
607
|
|
|
// } |
608
|
|
|
// } |
609
|
|
|
// } else { |
610
|
|
|
// $editor = new \XoopsFormEditor($caption, 'inbetween', $editor_configs); |
611
|
|
|
// } |
612
|
|
|
// break; |
613
|
|
|
|
614
|
|
|
// case 'koivi': |
615
|
|
|
// if (!$xoops22) { |
616
|
|
|
// if (is_readable(XOOPS_ROOT_PATH . '/class/wysiwyg/formwysiwygtextarea.php')) { |
617
|
|
|
// require_once XOOPS_ROOT_PATH . '/class/wysiwyg/formwysiwygtextarea.php'; |
618
|
|
|
// $editor = new \XoopsFormWysiwygTextArea($caption, $name, $value, '100%', '400px'); |
619
|
|
|
// } else { |
620
|
|
|
// if ($dhtml) { |
621
|
|
|
// $editor = new \XoopsFormDhtmlTextArea($caption, $name, $value, 20, 60); |
622
|
|
|
// } else { |
623
|
|
|
// $editor = new \XoopsFormTextArea($caption, $name, $value, 7, 60); |
624
|
|
|
// } |
625
|
|
|
// } |
626
|
|
|
// } else { |
627
|
|
|
// $editor = new \XoopsFormEditor($caption, 'koivi', $editor_configs); |
628
|
|
|
// } |
629
|
|
|
// break; |
630
|
|
|
|
631
|
|
|
// case 'htmlarea': |
632
|
|
|
// if (!$xoops22) { |
633
|
|
|
// if (is_readable(XOOPS_ROOT_PATH . '/class/htmlarea/formhtmlarea.php')) { |
634
|
|
|
// require_once XOOPS_ROOT_PATH . '/class/htmlarea/formhtmlarea.php'; |
635
|
|
|
// $editor = new \XoopsFormHtmlarea($caption, $name, $value); |
636
|
|
|
// } |
637
|
|
|
// } else { |
638
|
|
|
// $editor = new \XoopsFormEditor($caption, 'htmlarea', $editor_configs); |
639
|
|
|
// } |
640
|
|
|
// break; |
641
|
|
|
|
642
|
|
|
default: |
643
|
|
|
case 'textarea': |
|
|
|
|
644
|
|
|
$form_rows = isset($control['rows']) ? $control['rows'] : 5; |
645
|
|
|
$form_cols = isset($control['cols']) ? $control['cols'] : 60; |
646
|
|
|
|
647
|
|
|
$editor = new \XoopsFormTextArea($var['form_caption'], $key, $this->targetObject->getVar($key, 'e'), $form_rows, $form_cols); |
|
|
|
|
648
|
|
|
if ($var['form_dsc']) { |
649
|
|
|
$editor->setDescription($var['form_dsc']); |
650
|
|
|
} |
651
|
|
|
break; |
652
|
|
|
|
653
|
|
|
} |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
return $editor; |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
/** |
660
|
|
|
* @param $key |
661
|
|
|
* @param $var |
662
|
|
|
* @param bool $multiple |
663
|
|
|
* @return \XoopsFormSelect |
664
|
|
|
*/ |
665
|
|
|
public function getThemeSelect($key, $var, $multiple = false) |
666
|
|
|
{ |
667
|
|
|
$size = $multiple ? 5 : 1; |
668
|
|
|
$theme_select = new \XoopsFormSelect($var['form_caption'], $key, $this->targetObject->getVar($key), $size, $multiple); |
|
|
|
|
669
|
|
|
|
670
|
|
|
$handle = opendir(XOOPS_THEME_PATH . '/'); |
671
|
|
|
$dirlist = []; |
672
|
|
|
while (false !== ($file = readdir($handle))) { |
673
|
|
|
if (is_dir(XOOPS_THEME_PATH . '/' . $file) && !preg_match('/^[.]{1,2}$/', $file) |
674
|
|
|
&& 'cvs' !== strtolower($file)) { |
675
|
|
|
$dirlist[$file] = $file; |
676
|
|
|
} |
677
|
|
|
} |
678
|
|
|
closedir($handle); |
679
|
|
|
if (!empty($dirlist)) { |
680
|
|
|
asort($dirlist); |
681
|
|
|
$theme_select->addOptionArray($dirlist); |
682
|
|
|
} |
683
|
|
|
|
684
|
|
|
return $theme_select; |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
/** |
688
|
|
|
* @param $keyname |
689
|
|
|
* @return bool |
690
|
|
|
*/ |
691
|
|
|
public function &getElementById($keyname) |
692
|
|
|
{ |
693
|
|
|
foreach ($this->_elements as $eleObj) { |
694
|
|
|
if ($eleObj->getName() == $keyname) { |
695
|
|
|
$ret =& $eleObj; |
696
|
|
|
break; |
697
|
|
|
} |
698
|
|
|
} |
699
|
|
|
|
700
|
|
|
return isset($ret) ? $ret : false; |
701
|
|
|
} |
702
|
|
|
|
703
|
|
|
/** |
704
|
|
|
* create HTML to output the form as a theme-enabled table with validation. |
705
|
|
|
* |
706
|
|
|
* @return string |
707
|
|
|
*/ |
708
|
|
|
public function render() |
709
|
|
|
{ |
710
|
|
|
$required = $this->getRequired(); |
|
|
|
|
711
|
|
|
$ret = " |
712
|
|
|
<form name='" . $this->getName() . "' id='" . $this->getName() . "' action='" . $this->getAction() . "' method='" . $this->getMethod() . "' onsubmit='return xoopsFormValidate_" . $this->getName() . "(this);'" . $this->getExtra() . "> |
|
|
|
|
713
|
|
|
<table width='100%' class='outer' cellspacing='1'> |
714
|
|
|
<tr><th colspan='2'>" . $this->getTitle() . '</th></tr> |
715
|
|
|
'; |
716
|
|
|
$hidden = ''; |
717
|
|
|
$class = 'even'; |
718
|
|
|
foreach ($this->getElements() as $ele) { |
719
|
|
|
if (!is_object($ele)) { |
720
|
|
|
$ret .= $ele; |
721
|
|
|
} elseif (!$ele->isHidden()) { |
722
|
|
|
//$class = ( $class == 'even' ) ? 'odd': 'even'; |
723
|
|
|
$ret .= "<tr id='" . $ele->getName() . "' valign='top' align='left'><td class='head'>" . $ele->getCaption(); |
724
|
|
|
if ('' !== $ele->getDescription()) { |
725
|
|
|
$ret .= '<br><br><span style="font-weight: normal;">' . $ele->getDescription() . '</span>'; |
726
|
|
|
} |
727
|
|
|
$ret .= "</td><td class='$class'>" . $ele->render() . "</td></tr>\n"; |
728
|
|
|
} else { |
729
|
|
|
$hidden .= $ele->render(); |
730
|
|
|
} |
731
|
|
|
} |
732
|
|
|
$ret .= "</table>\n$hidden\n</form>\n"; |
733
|
|
|
$ret .= $this->renderValidationJS(true); |
734
|
|
|
|
735
|
|
|
return $ret; |
736
|
|
|
} |
737
|
|
|
|
738
|
|
|
/** |
739
|
|
|
* assign to smarty form template instead of displaying directly |
740
|
|
|
* |
741
|
|
|
* @param \XoopsTpl $tpl |
742
|
|
|
* |
743
|
|
|
* object |
744
|
|
|
* @param bool $smartyName |
745
|
|
|
* @see Smarty |
746
|
|
|
*/ |
747
|
|
|
public function assign(\XoopsTpl $tpl, $smartyName = false) |
748
|
|
|
{ |
749
|
|
|
$i = 0; |
750
|
|
|
$elements = []; |
751
|
|
|
foreach ($this->getElements() as $ele) { |
752
|
|
|
$n = ('' !== $ele->getName()) ? $ele->getName() : $i; |
753
|
|
|
$elements[$n]['name'] = $ele->getName(); |
754
|
|
|
$elements[$n]['caption'] = $ele->getCaption(); |
755
|
|
|
$elements[$n]['body'] = $ele->render(); |
756
|
|
|
$elements[$n]['hidden'] = $ele->isHidden(); |
757
|
|
|
$elements[$n]['section'] = strtolower(get_class($ele)) == strtolower('SmartFormSection'); |
758
|
|
|
$elements[$n]['section_close'] = $ele instanceof \XoopsModules\Smartobject\Form\Elements\SmartFormSectionClose; |
759
|
|
|
$elements[$n]['hide'] = isset($this->targetObject->vars[$n]['hide']) ? $this->targetObject->vars[$n]['hide'] : false; |
760
|
|
|
if ('' !== $ele->getDescription()) { |
761
|
|
|
$elements[$n]['description'] = $ele->getDescription(); |
762
|
|
|
} |
763
|
|
|
++$i; |
764
|
|
|
} |
765
|
|
|
$js = $this->renderValidationJS(); |
766
|
|
|
if (!$smartyName) { |
767
|
|
|
$smartyName = $this->getName(); |
|
|
|
|
768
|
|
|
} |
769
|
|
|
|
770
|
|
|
$tpl->assign($smartyName, [ |
771
|
|
|
'title' => $this->getTitle(), |
772
|
|
|
'name' => $this->getName(), |
|
|
|
|
773
|
|
|
'action' => $this->getAction(), |
774
|
|
|
'method' => $this->getMethod(), |
775
|
|
|
'extra' => 'onsubmit="return xoopsFormValidate_' . $this->getName() . '(this);"' . $this->getExtra(), |
|
|
|
|
776
|
|
|
'javascript' => $js, |
777
|
|
|
'elements' => $elements |
778
|
|
|
]); |
779
|
|
|
} |
780
|
|
|
|
781
|
|
|
/** |
782
|
|
|
* @param bool $withtags |
783
|
|
|
* @return string |
784
|
|
|
*/ |
785
|
|
|
public function renderValidationJS($withtags = true) |
786
|
|
|
{ |
787
|
|
|
$js = ''; |
788
|
|
|
if ($withtags) { |
789
|
|
|
$js .= "\n<!-- Start Form Validation JavaScript //-->\n<script type='text/javascript'>\n<!--//\n"; |
790
|
|
|
} |
791
|
|
|
$myts = \MyTextSanitizer::getInstance(); |
|
|
|
|
792
|
|
|
$formname = $this->getName(); |
|
|
|
|
793
|
|
|
$js .= "function xoopsFormValidate_{$formname}(myform) {"; |
794
|
|
|
// First, output code to check required elements |
795
|
|
|
$elements = $this->getRequired(); |
796
|
|
|
foreach ($elements as $elt) { |
797
|
|
|
$eltname = $elt->getName(); |
798
|
|
|
$eltcaption = trim($elt->getCaption()); |
799
|
|
|
$eltmsg = empty($eltcaption) ? sprintf(_FORM_ENTER, $eltname) : sprintf(_FORM_ENTER, $eltcaption); |
800
|
|
|
$eltmsg = str_replace('"', '\"', stripslashes($eltmsg)); |
801
|
|
|
if ('xoopsformradio' === strtolower(get_class($elt))) { |
802
|
|
|
$js .= 'var myOption = -1;'; |
803
|
|
|
$js .= "for (i=myform.{$eltname}.length-1; i > -1; i--) { |
804
|
|
|
if (myform.{$eltname}[i].checked) { |
805
|
|
|
myOption = i; i = -1; |
806
|
|
|
} |
807
|
|
|
} |
808
|
|
|
if (myOption == -1) { |
809
|
|
|
window.alert(\"{$eltmsg}\"); myform.{$eltname}[0].focus(); return false; }\n"; |
810
|
|
|
} elseif ('smartformselect_multielement' === strtolower(get_class($elt))) { |
811
|
|
|
$js .= 'var hasSelections = false;'; |
812
|
|
|
$js .= "for (var i = 0; i < myform['{$eltname}[]'].length; i++) { |
813
|
|
|
if (myform['{$eltname}[]'].options[i].selected) { |
814
|
|
|
hasSelections = true; |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
} |
818
|
|
|
if (hasSelections === false) { |
819
|
|
|
window.alert(\"{$eltmsg}\"); myform['{$eltname}[]'].options[0].focus(); return false; }\n"; |
820
|
|
|
} elseif ('xoopsformcheckbox' === strtolower(get_class($elt)) |
821
|
|
|
|| 'smartformcheckelement' === strtolower(get_class($elt))) { |
822
|
|
|
$js .= 'var hasSelections = false;'; |
823
|
|
|
//sometimes, there is an implicit '[]', sometimes not |
824
|
|
View Code Duplication |
if (false === strpos($eltname, '[')) { |
|
|
|
|
825
|
|
|
$js .= "for (var i = 0; i < myform['{$eltname}[]'].length; i++) { |
826
|
|
|
if (myform['{$eltname}[]'][i].checked) { |
827
|
|
|
hasSelections = true; |
828
|
|
|
} |
829
|
|
|
|
830
|
|
|
} |
831
|
|
|
if (hasSelections === false) { |
832
|
|
|
window.alert(\"{$eltmsg}\"); myform['{$eltname}[]'][0].focus(); return false; }\n"; |
833
|
|
|
} else { |
834
|
|
|
$js .= "for (var i = 0; i < myform['{$eltname}'].length; i++) { |
835
|
|
|
if (myform['{$eltname}'][i].checked) { |
836
|
|
|
hasSelections = true; |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
} |
840
|
|
|
if (hasSelections === false) { |
841
|
|
|
window.alert(\"{$eltmsg}\"); myform['{$eltname}'][0].focus(); return false; }\n"; |
842
|
|
|
} |
843
|
|
|
} else { |
844
|
|
|
$js .= "if ( myform.{$eltname}.value == \"\" ) " . "{ window.alert(\"{$eltmsg}\"); myform.{$eltname}.focus(); return false; }\n"; |
845
|
|
|
} |
846
|
|
|
} |
847
|
|
|
// Now, handle custom validation code |
848
|
|
|
$elements =& $this->getElements(true); |
849
|
|
|
foreach ($elements as $elt) { |
850
|
|
|
if (method_exists($elt, 'renderValidationJS') && 'xoopsformcheckbox' !== strtolower(get_class($elt))) { |
851
|
|
|
if ($eltjs = $elt->renderValidationJS()) { |
852
|
|
|
$js .= $eltjs . "\n"; |
853
|
|
|
} |
854
|
|
|
} |
855
|
|
|
} |
856
|
|
|
$js .= "return true;\n}\n"; |
857
|
|
|
if ($withtags) { |
858
|
|
|
$js .= "//--></script>\n<!-- 'End Form Validation JavaScript' //-->\n"; |
859
|
|
|
} |
860
|
|
|
|
861
|
|
|
return $js; |
862
|
|
|
} |
863
|
|
|
} |
864
|
|
|
|
This check looks for assignments to scalar types that may be of the wrong type.
To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.