SM doesn't know how to log in again on the same connection, so best to actually close...
[squirrelmail.git] / functions / options.php
CommitLineData
44ef0f47 1<?php
2ba13803 2
35586184 3/**
4 * options.php
5 *
35586184 6 * Functions needed to display the options pages.
7 *
22387c8d 8 * @copyright 1999-2017 The SquirrelMail Project Team
4b4abf93 9 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
31841a9e 10 * @version $Id$
d6c32258 11 * @package squirrelmail
ca479ad1 12 * @subpackage prefs
35586184 13 */
a3ec3c91 14
9962527a 15/**
598294a7 16 * SquirrelOption: An option for SquirrelMail.
9962527a 17 *
8f6f9ba5 18 * @package squirrelmail
b4856b14 19 * @subpackage prefs
9962527a 20 */
21class SquirrelOption {
d789daf0 22 /**
23 * The original option configuration array
24 * @var array
25 */
26 var $raw_option_array;
b4856b14 27 /**
28 * The name of this setting
29 * @var string
30 */
9962527a 31 var $name;
b4856b14 32 /**
33 * The text that prefaces setting on the preferences page
34 * @var string
35 */
9962527a 36 var $caption;
e40b0e8e 37 /**
38 * Whether or not the caption text is allowed to wrap
39 * @var boolean
40 */
41 var $caption_wrap;
b4856b14 42 /**
43 * The type of INPUT element
44 *
45 * See SMOPT_TYPE_* defines
46 * @var integer
47 */
9962527a 48 var $type;
b4856b14 49 /**
598294a7 50 * Indicates if a link should be shown to refresh part
b4856b14 51 * or all of the window
52 *
53 * See SMOPT_REFRESH_* defines
54 * @var integer
55 */
a3ec3c91 56 var $refresh_level;
b4856b14 57 /**
58 * Specifies the size of certain input items
59 *
60 * See SMOPT_SIZE_* defines
61 * @var integer
62 */
bbcafebd 63 var $size;
b4856b14 64 /**
598294a7 65 * Text that follows a text input or
b4856b14 66 * select list input on the preferences page
598294a7 67 *
b4856b14 68 * useful for indicating units, meanings of special values, etc.
69 * @var string
70 */
2d24b622 71//TODO: add trailing_text_small as has been done with 1.4.x
361d6e1b 72 var $trailing_text;
5b277d00 73 /**
74 * Text that overrides the "Yes" label for boolean
75 * radio option widgets
76 *
77 * @var string
78 */
79 var $yes_text;
80 /**
81 * Text that overrides the "No" label for boolean
82 * radio option widgets
83 *
84 * @var string
85 */
86 var $no_text;
52639d23 87 /**
88 * Some widgets support more than one layout type
89 *
90 * @var int
91 */
92 var $layout_type;
b6a08d2d 93 /**
94 * Indicates if the Add widget should be included
95 * with edit lists.
96 *
97 * @var boolean
98 */
99 var $use_add_widget;
de4c101c 100 /**
101 * Indicates if the Delete widget should be included
102 * with edit lists.
103 *
104 * @var boolean
105 */
106 var $use_delete_widget;
282f8e7c 107 /**
108 * associative array, treated the same as $possible_values
109 * (see its documentation below), but usually expected to
110 * have its first value contain a list of IMAP folders, an
111 * array itself in the format as passed back by
112 * sqimap_mailbox_list(). Used to display folder selector
113 * for possible values of an associative edit list option
114 * widget
115 *
116 * @since 1.5.2
117 * @var array
118 */
119 var $poss_value_folders;
b4856b14 120 /**
121 * text displayed to the user
122 *
123 * Used with SMOPT_TYPE_COMMENT options
124 * @var string
125 */
bbcafebd 126 var $comment;
b4856b14 127 /**
0177059f 128 * additional javascript or other widget attributes added to the
129 * user input; must be an array where keys are attribute names
130 * ("onclick", etc) and values are the attribute values.
131 * @var array
b4856b14 132 */
0177059f 133 var $aExtraAttribs;
b4856b14 134 /**
598294a7 135 * script (usually Javascript) that will be placed after (outside of)
b4856b14 136 * the INPUT tag
137 * @var string
138 */
6ae9e729 139 var $post_script;
cbe5423b 140
b4856b14 141 /**
142 * The name of the Save Function for this option.
143 * @var string
144 */
cbe5423b 145 var $save_function;
9962527a 146
147 /* The various 'values' for this options. */
b4856b14 148 /**
149 * default/preselected value for this option
150 * @var mixed
151 */
9962527a 152 var $value;
b4856b14 153 /**
154 * new option value
155 * @var mixed
156 */
9962527a 157 var $new_value;
b4856b14 158 /**
598294a7 159 * associative array, where each key is an actual input value
b4856b14 160 * and the corresponding value is what is displayed to the user
161 * for that list item in the drop-down list
162 * @var array
163 */
a3ec3c91 164 var $possible_values;
b4856b14 165 /**
166 * disables html sanitizing.
598294a7 167 *
168 * WARNING - don't use it, if user input is possible in option
0177059f 169 * or use own sanitizing functions. Currently only works for SMOPT_TYPE_STRLIST.
b4856b14 170 * @var bool
171 */
28520c87 172 var $htmlencoded=false;
99ecf044 173 /**
42b7c9d4 174 * Controls folder list limits in SMOPT_TYPE_FLDRLIST and
282f8e7c 175 * SMOPT_TYPE_FLDRLIST_MULTI widgets as well as the optional
176 * embedded folder lists provided for inputting values for
177 * the SMOPT_TYPE_EDIT_LIST and SMOPT_TYPE_EDIT_LIST_ASSOCIATIVE
178 * :idgets.
99ecf044 179 * See $flag argument in sqimap_mailbox_option_list() function.
180 * @var string
181 * @since 1.5.1
182 */
183 var $folder_filter='noselect';
9962527a 184
b4856b14 185 /**
b4d52882 186 * Constructor (PHP5 style, required in some future version of PHP)
d789daf0 187 * @param array $raw_option_array
b4856b14 188 * @param string $name
189 * @param string $caption
190 * @param integer $type
191 * @param integer $refresh_level
192 * @param mixed $initial_value
193 * @param array $possible_values
194 * @param bool $htmlencoded
195 */
b4d52882 196 function __construct
d789daf0 197 ($raw_option_array, $name, $caption, $type, $refresh_level, $initial_value = '', $possible_values = '', $htmlencoded = false) {
9962527a 198 /* Set the basic stuff. */
d789daf0 199 $this->raw_option_array = $raw_option_array;
9962527a 200 $this->name = $name;
201 $this->caption = $caption;
e40b0e8e 202 $this->caption_wrap = TRUE;
9962527a 203 $this->type = $type;
a3ec3c91 204 $this->refresh_level = $refresh_level;
205 $this->possible_values = $possible_values;
28520c87 206 $this->htmlencoded = $htmlencoded;
b1dcab7e 207 $this->size = SMOPT_SIZE_NORMAL;
361d6e1b 208 $this->trailing_text = '';
5b277d00 209 $this->yes_text = '';
210 $this->no_text = '';
bbcafebd 211 $this->comment = '';
52639d23 212 $this->layout_type = 0;
b6a08d2d 213 $this->use_add_widget = TRUE;
de4c101c 214 $this->use_delete_widget = TRUE;
282f8e7c 215 $this->poss_value_folders = '';
0177059f 216 $this->aExtraAttribs = array();
6ae9e729 217 $this->post_script = '';
a3ec3c91 218
991c88e7 219 //Check for a current value.
220 if (isset($GLOBALS[$name])) {
a3ec3c91 221 $this->value = $GLOBALS[$name];
17f3d242 222 } else if (!empty($initial_value)) {
223 $this->value = $initial_value;
a3ec3c91 224 } else {
225 $this->value = '';
226 }
9962527a 227
a3ec3c91 228 /* Check for a new value. */
b4856b14 229 if ( !sqgetGlobalVar("new_$name", $this->new_value, SQ_POST ) ) {
59fc0b63 230 $this->new_value = NULL;
44ef0f47 231 }
cbe5423b 232
233 /* Set the default save function. */
6c06cf54 234 if ($type != SMOPT_TYPE_HIDDEN
235 && $type != SMOPT_TYPE_INFO
236 && $type != SMOPT_TYPE_COMMENT) {
cbe5423b 237 $this->save_function = SMOPT_SAVE_DEFAULT;
238 } else {
239 $this->save_function = SMOPT_SAVE_NOOP;
240 }
241 }
242
b4d52882 243 /**
244 * Constructor (PHP4 style, kept for compatibility reasons)
245 * @param array $raw_option_array
246 * @param string $name
247 * @param string $caption
248 * @param integer $type
249 * @param integer $refresh_level
250 * @param mixed $initial_value
251 * @param array $possible_values
252 * @param bool $htmlencoded
253 */
254 function SquirrelOption
255 ($raw_option_array, $name, $caption, $type, $refresh_level, $initial_value = '', $possible_values = '', $htmlencoded = false) {
256 self::__construct($raw_option_array, $name, $caption, $type, $refresh_level, $initial_value, $possible_values, $htmlencoded);
257 }
258
5a42c101 259 /** Convenience function that identifies which types of
260 widgets are stored as (serialized) array values. */
261 function is_multiple_valued() {
262 return ($this->type == SMOPT_TYPE_FLDRLIST_MULTI
263 || $this->type == SMOPT_TYPE_STRLIST_MULTI
282f8e7c 264 || $this->type == SMOPT_TYPE_EDIT_LIST
265 || $this->type == SMOPT_TYPE_EDIT_LIST_ASSOCIATIVE);
5a42c101 266 }
267
b4856b14 268 /**
269 * Set the value for this option.
270 * @param mixed $value
271 */
cbe5423b 272 function setValue($value) {
273 $this->value = $value;
274 }
275
b4856b14 276 /**
277 * Set the new value for this option.
278 * @param mixed $new_value
279 */
cbe5423b 280 function setNewValue($new_value) {
281 $this->new_value = $new_value;
9962527a 282 }
44ef0f47 283
e40b0e8e 284 /**
285 * Set whether the caption is allowed to wrap for this option.
286 * @param boolean $caption_wrap
287 */
288 function setCaptionWrap($caption_wrap) {
289 $this->caption_wrap = $caption_wrap;
290 }
291
b4856b14 292 /**
293 * Set the size for this option.
294 * @param integer $size
295 */
bbcafebd 296 function setSize($size) {
297 $this->size = $size;
298 }
299
b4856b14 300 /**
301 * Set the trailing_text for this option.
302 * @param string $trailing_text
303 */
361d6e1b 304 function setTrailingText($trailing_text) {
305 $this->trailing_text = $trailing_text;
306 }
307
5b277d00 308 /**
309 * Set the yes_text for this option.
310 * @param string $yes_text
311 */
312 function setYesText($yes_text) {
313 $this->yes_text = $yes_text;
314 }
315
316 /**
317 * Set the no_text for this option.
318 * @param string $no_text
319 */
320 function setNoText($no_text) {
321 $this->no_text = $no_text;
322 }
323
b6a08d2d 324 /* Set the "use add widget" value for this option. */
325 function setUseAddWidget($use_add_widget) {
326 $this->use_add_widget = $use_add_widget;
327 }
328
de4c101c 329 /* Set the "use delete widget" value for this option. */
330 function setUseDeleteWidget($use_delete_widget) {
331 $this->use_delete_widget = $use_delete_widget;
332 }
333
282f8e7c 334 /* Set the "poss value folders" value for this option.
335 See the associative edit list widget, which uses this
336 to offer folder list selection for the values */
337 function setPossValueFolders($poss_value_folders) {
338 $this->poss_value_folders = $poss_value_folders;
339 }
340
52639d23 341 /**
342 * Set the layout type for this option.
343 * @param int $layout_type
344 */
345 function setLayoutType($layout_type) {
346 $this->layout_type = $layout_type;
347 }
348
b4856b14 349 /**
350 * Set the comment for this option.
351 * @param string $comment
352 */
bbcafebd 353 function setComment($comment) {
354 $this->comment = $comment;
355 }
356
b4856b14 357 /**
0177059f 358 * Set the extra attributes for this option.
359 * @param array $aExtraAttribs
b4856b14 360 */
0177059f 361 function setExtraAttributes($aExtraAttribs) {
362 $this->aExtraAttribs = $aExtraAttribs;
cbe5423b 363 }
364
b4856b14 365 /**
366 * Set the "post script" for this option.
367 * @param string $post_script
368 */
6ae9e729 369 function setPostScript($post_script) {
370 $this->post_script = $post_script;
371 }
372
b4856b14 373 /**
374 * Set the save function for this option.
375 * @param string $save_function
376 */
cbe5423b 377 function setSaveFunction($save_function) {
378 $this->save_function = $save_function;
379 }
380
99ecf044 381 /**
5b277d00 382 * Set the folder_filter for this option.
99ecf044 383 * @param string $folder_filter
384 * @since 1.5.1
385 */
386 function setFolderFilter($folder_filter) {
387 $this->folder_filter = $folder_filter;
388 }
389
b4856b14 390 /**
391 * Creates fields on option pages according to option type
392 *
9786ea94 393 * This is the function that calls all other createWidget* functions.
394 *
395 * @return string The formated option field
396 *
b4856b14 397 */
9786ea94 398 function createWidget() {
ce68b76b 399 global $color;
cbe5423b 400
62f7daa5 401 // Use new value if available
59fc0b63 402 if (!is_null($this->new_value)) {
74e44765 403 $tempValue = $this->value;
404 $this->value = $this->new_value;
405 }
406
cbe5423b 407 /* Get the widget for this option type. */
a3ec3c91 408 switch ($this->type) {
3fa09710 409 case SMOPT_TYPE_PASSWORD:
410 $result = $this->createWidget_String(TRUE);
411 break;
a3ec3c91 412 case SMOPT_TYPE_STRING:
37a3ed17 413 $result = $this->createWidget_String();
a3ec3c91 414 break;
415 case SMOPT_TYPE_STRLIST:
37a3ed17 416 $result = $this->createWidget_StrList();
a3ec3c91 417 break;
7e6d5ea3 418 case SMOPT_TYPE_TEXTAREA:
37a3ed17 419 $result = $this->createWidget_TextArea();
a3ec3c91 420 break;
421 case SMOPT_TYPE_INTEGER:
37a3ed17 422 $result = $this->createWidget_Integer();
a3ec3c91 423 break;
424 case SMOPT_TYPE_FLOAT:
37a3ed17 425 $result = $this->createWidget_Float();
a3ec3c91 426 break;
427 case SMOPT_TYPE_BOOLEAN:
37a3ed17 428 $result = $this->createWidget_Boolean();
a3ec3c91 429 break;
1b7db98b 430 case SMOPT_TYPE_BOOLEAN_CHECKBOX:
431 $result = $this->createWidget_Boolean(TRUE);
432 break;
8b2726c5 433 case SMOPT_TYPE_BOOLEAN_RADIO:
434 $result = $this->createWidget_Boolean(FALSE);
435 break;
2a50fbd7 436 case SMOPT_TYPE_HIDDEN:
37a3ed17 437 $result = $this->createWidget_Hidden();
a3ec3c91 438 break;
bbcafebd 439 case SMOPT_TYPE_COMMENT:
37a3ed17 440 $result = $this->createWidget_Comment();
bbcafebd 441 break;
be2d5495 442 case SMOPT_TYPE_FLDRLIST:
37a3ed17 443 $result = $this->createWidget_FolderList();
be2d5495 444 break;
42b7c9d4 445 case SMOPT_TYPE_FLDRLIST_MULTI:
446 $result = $this->createWidget_FolderList(TRUE);
447 break;
38d93650 448 case SMOPT_TYPE_EDIT_LIST:
449 $result = $this->createWidget_EditList();
450 break;
282f8e7c 451 case SMOPT_TYPE_EDIT_LIST_ASSOCIATIVE:
452 $result = $this->createWidget_EditListAssociative();
453 break;
40268626 454 case SMOPT_TYPE_STRLIST_MULTI:
455 $result = $this->createWidget_StrList(TRUE);
456 break;
daf77710 457 case SMOPT_TYPE_STRLIST_RADIO:
458 $result = $this->createWidget_StrList(FALSE, TRUE);
459 break;
b6a08d2d 460 case SMOPT_TYPE_SUBMIT:
461 $result = $this->createWidget_Submit();
462 break;
6c06cf54 463 case SMOPT_TYPE_INFO:
464 $result = $this->createWidget_Info();
465 break;
a3ec3c91 466 default:
fb8c4296 467 error_box (
468 sprintf(_("Option Type '%s' Not Found"), $this->type)
469 );
a3ec3c91 470 }
471
6ae9e729 472 /* Add the "post script" for this option. */
473 $result .= $this->post_script;
62f7daa5 474
74e44765 475 // put correct value back if need be
59fc0b63 476 if (!is_null($this->new_value)) {
74e44765 477 $this->value = $tempValue;
478 }
479
a3ec3c91 480 /* Now, return the created widget. */
9786ea94 481 return $result;
a3ec3c91 482 }
483
6c06cf54 484 /**
485 * Creates info block
486 * @return string html formated output
487 */
488 function createWidget_Info() {
2d24b622 489 // return sq_htmlspecialchars($this->value);
490 // like COMMENT, allow HTML here
491 return $this->value;
6c06cf54 492 }
493
b4856b14 494 /**
495 * Create string field
3fa09710 496 *
497 * @param boolean $password When TRUE, the text in the input
498 * widget will be obscured (OPTIONAL;
499 * default = FALSE).
500 *
b4856b14 501 * @return string html formated option field
3fa09710 502 *
b4856b14 503 */
3fa09710 504 function createWidget_String($password=FALSE) {
bbcafebd 505 switch ($this->size) {
88cb1b4d 506 case SMOPT_SIZE_TINY:
507 $width = 5;
508 break;
509 case SMOPT_SIZE_SMALL:
510 $width = 12;
511 break;
512 case SMOPT_SIZE_LARGE:
513 $width = 38;
514 break;
515 case SMOPT_SIZE_HUGE:
516 $width = 50;
517 break;
bbcafebd 518 case SMOPT_SIZE_NORMAL:
88cb1b4d 519 default:
520 $width = 25;
bbcafebd 521 }
522
f08c3bcc 523//TODO: might be better to have a separate template file for all widgets, because then the layout of the widget and the "trailing text" can be customized - they are still hard coded here
3fa09710 524 if ($password)
3047e291 525 return addPwField('new_' . $this->name, $this->value, $width, 0, $this->aExtraAttribs) . ' ' . sm_encode_html_special_chars($this->trailing_text);
3fa09710 526 else
3047e291 527 return addInput('new_' . $this->name, $this->value, $width, 0, $this->aExtraAttribs) . ' ' . sm_encode_html_special_chars($this->trailing_text);
a3ec3c91 528 }
529
b4856b14 530 /**
daf77710 531 * Create selection box or radio button group
0177059f 532 *
533 * When $this->htmlencoded is TRUE, the keys and values in
534 * $this->possible_values are assumed to be display-safe.
535 * Use with care!
536 *
daf77710 537 * Note that when building radio buttons instead of a select
538 * widget, if the "size" attribute is SMOPT_SIZE_TINY, the
539 * radio buttons will be output one after another without
540 * linebreaks between them. Otherwise, each radio button
541 * goes on a line of its own.
542 *
543 * @param boolean $multiple_select When TRUE, the select widget
40268626 544 * will allow multiple selections
daf77710 545 * (OPTIONAL; default is FALSE
40268626 546 * (single select list))
daf77710 547 * @param boolean $radio_buttons When TRUE, the widget will
548 * instead be built as a group
549 * of radio buttons (and
550 * $multiple_select will be
551 * forced to FALSE) (OPTIONAL;
552 * default is FALSE (select widget))
40268626 553 *
daf77710 554 * @return string html formated selection box or radio buttons
40268626 555 *
b4856b14 556 */
daf77710 557 function createWidget_StrList($multiple_select=FALSE, $radio_buttons=FALSE) {
98e88751 558//FIXME: Currently, $this->htmlencoded is ignored here -- was removed when changing to template-based output; a fix is available as part of proposed centralized sanitizing patch
40268626 559
daf77710 560 // radio buttons instead of select widget?
561 //
562 if ($radio_buttons) {
563
564 global $br, $nbsp;
565 $result = '';
566 foreach ($this->possible_values as $real_value => $disp_value) {
567 $result .= addRadioBox('new_' . $this->name, ($this->value == $real_value), $real_value, array_merge(array('id' => 'new_' . $this->name . '_' . $real_value), $this->aExtraAttribs)) . $nbsp . create_label($disp_value, 'new_' . $this->name . '_' . $real_value);
568 if ($this->size != SMOPT_SIZE_TINY)
569 $result .= $br;
570 }
571
572 return $result;
573 }
574
575
576 // everything below applies to select widgets
577 //
40268626 578 switch ($this->size) {
579//FIXME: not sure about these sizes... seems like we could add another on the "large" side...
580 case SMOPT_SIZE_TINY:
581 $height = 3;
582 break;
583 case SMOPT_SIZE_SMALL:
584 $height = 8;
585 break;
586 case SMOPT_SIZE_LARGE:
587 $height = 15;
588 break;
589 case SMOPT_SIZE_HUGE:
590 $height = 25;
591 break;
592 case SMOPT_SIZE_NORMAL:
593 default:
594 $height = 5;
595 }
596
3047e291 597 return addSelect('new_' . $this->name, $this->possible_values, $this->value, TRUE, $this->aExtraAttribs, $multiple_select, $height, !$this->htmlencoded) . sm_encode_html_special_chars($this->trailing_text);
a3ec3c91 598
a3ec3c91 599 }
600
b4856b14 601 /**
602 * Create folder selection box
42b7c9d4 603 *
604 * @param boolean $multiple_select When TRUE, the select widget
605 * will allow multiple selections
606 * (OPTIONAL; default is FALSE
607 * (single select list))
608 *
b4856b14 609 * @return string html formated selection box
42b7c9d4 610 *
b4856b14 611 */
42b7c9d4 612 function createWidget_FolderList($multiple_select=FALSE) {
be2d5495 613
38d93650 614 switch ($this->size) {
615//FIXME: not sure about these sizes... seems like we could add another on the "large" side...
616 case SMOPT_SIZE_TINY:
617 $height = 3;
618 break;
619 case SMOPT_SIZE_SMALL:
620 $height = 8;
621 break;
622 case SMOPT_SIZE_LARGE:
623 $height = 15;
624 break;
625 case SMOPT_SIZE_HUGE:
626 $height = 25;
627 break;
628 case SMOPT_SIZE_NORMAL:
629 default:
630 $height = 5;
631 }
632
0177059f 633 // possible values might include a nested array of
634 // possible values (list of folders)
635 //
636 $option_list = array();
637 foreach ($this->possible_values as $value => $text) {
62f7daa5 638
0177059f 639 // list of folders (boxes array)
640 //
641 if (is_array($text)) {
42b7c9d4 642 $option_list = array_merge($option_list, sqimap_mailbox_option_array(0, 0, $text, $this->folder_filter));
62f7daa5 643
0177059f 644 // just one option here
645 //
646 } else {
647 $option_list = array_merge($option_list, array($value => $text));
be2d5495 648 }
0177059f 649
62f7daa5 650 }
0177059f 651 if (empty($option_list))
652 $option_list = array('ignore' => _("unavailable"));
99ecf044 653
654
3047e291 655 return addSelect('new_' . $this->name, $option_list, $this->value, TRUE, $this->aExtraAttribs, $multiple_select, $height) . sm_encode_html_special_chars($this->trailing_text);
0177059f 656
be2d5495 657 }
658
b4856b14 659 /**
660 * Creates textarea
661 * @return string html formated textarea field
662 */
37a3ed17 663 function createWidget_TextArea() {
bbcafebd 664 switch ($this->size) {
665 case SMOPT_SIZE_TINY: $rows = 3; $cols = 10; break;
666 case SMOPT_SIZE_SMALL: $rows = 4; $cols = 30; break;
667 case SMOPT_SIZE_LARGE: $rows = 10; $cols = 60; break;
668 case SMOPT_SIZE_HUGE: $rows = 20; $cols = 80; break;
669 case SMOPT_SIZE_NORMAL:
670 default: $rows = 5; $cols = 50;
671 }
ba556ce5 672 return addTextArea('new_' . $this->name, $this->value, $cols, $rows, $this->aExtraAttribs);
a3ec3c91 673 }
674
b4856b14 675 /**
676 * Creates field for integer
677 *
678 * Difference from createWidget_String is visible only when javascript is enabled
679 * @return string html formated option field
680 */
37a3ed17 681 function createWidget_Integer() {
0d08ea5a 682
b65d1a08 683 // add onChange javascript handler to a regular string widget
684 // which will strip out all non-numeric chars
83aff890 685 if (checkForJavascript())
0177059f 686 $this->aExtraAttribs['onchange'] = 'origVal=this.value; newVal=\'\'; '
b65d1a08 687 . 'for (i=0;i<origVal.length;i++) { if (origVal.charAt(i)>=\'0\' '
688 . '&& origVal.charAt(i)<=\'9\') newVal += origVal.charAt(i); } '
0177059f 689 . 'this.value=newVal;';
690
691 return $this->createWidget_String();
a3ec3c91 692 }
693
b4856b14 694 /**
695 * Creates field for floating number
696 * Difference from createWidget_String is visible only when javascript is enabled
697 * @return string html formated option field
698 */
37a3ed17 699 function createWidget_Float() {
37a3ed17 700
b65d1a08 701 // add onChange javascript handler to a regular string widget
62f7daa5 702 // which will strip out all non-numeric (period also OK) chars
83aff890 703 if (checkForJavascript())
0177059f 704 $this->aExtraAttribs['onchange'] = 'origVal=this.value; newVal=\'\'; '
b65d1a08 705 . 'for (i=0;i<origVal.length;i++) { if ((origVal.charAt(i)>=\'0\' '
706 . '&& origVal.charAt(i)<=\'9\') || origVal.charAt(i)==\'.\') '
0177059f 707 . 'newVal += origVal.charAt(i); } this.value=newVal;';
708
709 return $this->createWidget_String();
a3ec3c91 710 }
711
b4856b14 712 /**
1b7db98b 713 * Create boolean widget
714 *
5b277d00 715 * When creating Yes/No radio buttons, the "yes_text"
716 * and "no_text" option attributes are used to override
717 * the typical "Yes" and "No" text.
718 *
1b7db98b 719 * @param boolean $checkbox When TRUE, the widget will be
720 * constructed as a checkbox,
721 * otherwise it will be a set of
722 * Yes/No radio buttons (OPTIONAL;
3b6a455c 723 * default is TRUE (checkbox)).
1b7db98b 724 *
725 * @return string html formated boolean widget
726 *
b4856b14 727 */
3b6a455c 728 function createWidget_Boolean($checkbox=TRUE) {
0177059f 729
5f88daeb 730 global $oTemplate, $nbsp;
fd87494d 731
fd87494d 732
1b7db98b 733 // checkbox...
734 //
735 if ($checkbox) {
736 $result = addCheckbox('new_' . $this->name, ($this->value != SMPREF_NO), SMPREF_YES, array_merge(array('id' => 'new_' . $this->name), $this->aExtraAttribs)) . $nbsp . create_label($this->trailing_text, 'new_' . $this->name);
737 }
738
739 // radio buttons...
740 //
741 else {
742
743 /* Build the yes choice. */
5b277d00 744 $yes_option = addRadioBox('new_' . $this->name, ($this->value != SMPREF_NO), SMPREF_YES, array_merge(array('id' => 'new_' . $this->name . '_yes'), $this->aExtraAttribs)) . $nbsp . create_label((!empty($this->yes_text) ? $this->yes_text : _("Yes")), 'new_' . $this->name . '_yes');
1b7db98b 745
746 /* Build the no choice. */
5b277d00 747 $no_option = addRadioBox('new_' . $this->name, ($this->value == SMPREF_NO), SMPREF_NO, array_merge(array('id' => 'new_' . $this->name . '_no'), $this->aExtraAttribs)) . $nbsp . create_label((!empty($this->no_text) ? $this->no_text : _("No")), 'new_' . $this->name . '_no');
1b7db98b 748
749 /* Build the combined "boolean widget". */
750 $result = "$yes_option$nbsp$nbsp$nbsp$nbsp$no_option";
751
752 }
fd87494d 753
fd87494d 754 return ($result);
a3ec3c91 755 }
756
b4856b14 757 /**
758 * Creates hidden field
759 * @return string html formated hidden input field
760 */
37a3ed17 761 function createWidget_Hidden() {
0177059f 762 return addHidden('new_' . $this->name, $this->value, $this->aExtraAttribs);
a3ec3c91 763 }
764
b4856b14 765 /**
766 * Creates comment
767 * @return string comment
768 */
37a3ed17 769 function createWidget_Comment() {
bbcafebd 770 $result = $this->comment;
771 return ($result);
772 }
773
38d93650 774 /**
282f8e7c 775 * Creates a (non-associative) edit list
52639d23 776 *
777 * Note that multiple layout types are supported for this widget.
778 * $this->layout_type must be one of the SMOPT_EDIT_LIST_LAYOUT_*
779 * constants.
780 *
38d93650 781 * @return string html formated list of edit fields and
782 * their associated controls
783 */
784 function createWidget_EditList() {
785
cb606dfd 786 global $oTemplate;
38d93650 787
788 switch ($this->size) {
38d93650 789 case SMOPT_SIZE_TINY:
790 $height = 3;
791 break;
792 case SMOPT_SIZE_SMALL:
793 $height = 8;
794 break;
b1dcab7e 795 case SMOPT_SIZE_MEDIUM:
38d93650 796 $height = 15;
797 break;
b1dcab7e 798 case SMOPT_SIZE_LARGE:
38d93650 799 $height = 25;
800 break;
b1dcab7e 801 case SMOPT_SIZE_HUGE:
802 $height = 40;
803 break;
38d93650 804 case SMOPT_SIZE_NORMAL:
805 default:
806 $height = 5;
807 }
808
dd6f9627 809 if (empty($this->possible_values)) $this->possible_values = array();
2ebfc729 810 if (!is_array($this->possible_values)) $this->possible_values = array($this->possible_values);
dd6f9627 811
cb606dfd 812//FIXME: $this->aExtraAttribs probably should only be used in one place
813 $oTemplate->assign('input_widget', addInput('add_' . $this->name, '', 38, 0, $this->aExtraAttribs));
b6a08d2d 814 $oTemplate->assign('use_input_widget', $this->use_add_widget);
de4c101c 815 $oTemplate->assign('use_delete_widget', $this->use_delete_widget);
b6a08d2d 816
cb606dfd 817 $oTemplate->assign('trailing_text', $this->trailing_text);
52639d23 818 $oTemplate->assign('possible_values', $this->possible_values);
282f8e7c 819 $oTemplate->assign('current_value', $this->value);
820 $oTemplate->assign('select_widget', addSelect('new_' . $this->name, $this->possible_values, $this->value, FALSE, !checkForJavascript() ? $this->aExtraAttribs : array_merge(array('onchange' => 'if (typeof(window.addinput_' . $this->name . ') == \'undefined\') { var f = document.forms.length; var i = 0; var pos = -1; while( pos == -1 && i < f ) { var e = document.forms[i].elements.length; var j = 0; while( pos == -1 && j < e ) { if ( document.forms[i].elements[j].type == \'text\' && document.forms[i].elements[j].name == \'add_' . $this->name . '\' ) { pos = j; i=f-1; j=e-1; } j++; } i++; } if( pos >= 0 ) { window.addinput_' . $this->name . ' = document.forms[i-1].elements[pos]; } } for (x = 0; x < this.length; x++) { if (this.options[x].selected) { window.addinput_' . $this->name . '.value = this.options[x].text; break; } }'), $this->aExtraAttribs), TRUE, $height));
821// NOTE: i=f-1; j=e-1 is in lieu of break 2
cb606dfd 822 $oTemplate->assign('checkbox_widget', addCheckBox('delete_' . $this->name, FALSE, SMPREF_YES, array_merge(array('id' => 'delete_' . $this->name), $this->aExtraAttribs)));
823 $oTemplate->assign('name', $this->name);
52639d23 824
825 switch ($this->layout_type) {
826 case SMOPT_EDIT_LIST_LAYOUT_SELECT:
827 return $oTemplate->fetch('edit_list_widget.tpl');
828 case SMOPT_EDIT_LIST_LAYOUT_LIST:
829 return $oTemplate->fetch('edit_list_widget_list_style.tpl');
830 default:
282f8e7c 831 error_box(sprintf(_("Edit List Layout Type '%s' Not Found"), $this->layout_type));
832 }
833
834 }
835
836 /**
837 * Creates an associative edit list
838 *
839 * Note that multiple layout types are supported for this widget.
840 * $this->layout_type must be one of the SMOPT_EDIT_LIST_LAYOUT_*
841 * constants.
842 *
843 * @return string html formated list of edit fields and
844 * their associated controls
845 */
846 function createWidget_EditListAssociative() {
847
848 global $oTemplate;
849
850 switch ($this->size) {
851 case SMOPT_SIZE_TINY:
852 $height = 3;
853 break;
854 case SMOPT_SIZE_SMALL:
855 $height = 8;
856 break;
857 case SMOPT_SIZE_MEDIUM:
858 $height = 15;
859 break;
860 case SMOPT_SIZE_LARGE:
861 $height = 25;
862 break;
863 case SMOPT_SIZE_HUGE:
864 $height = 40;
865 break;
866 case SMOPT_SIZE_NORMAL:
867 default:
868 $height = 5;
869 }
870
871
872 // ensure correct format of current value(s)
873 //
874 if (empty($this->possible_values)) $this->possible_values = array();
875 if (!is_array($this->possible_values)) $this->possible_values = array($this->possible_values);
876
877
878 $oTemplate->assign('name', $this->name);
879 $oTemplate->assign('current_value', $this->value);
880 $oTemplate->assign('possible_values', $this->possible_values);
881 $oTemplate->assign('poss_value_folders', $this->poss_value_folders);
882 $oTemplate->assign('folder_filter', $this->folder_filter);
883
884 $oTemplate->assign('use_input_widget', $this->use_add_widget);
885 $oTemplate->assign('use_delete_widget', $this->use_delete_widget);
886
887 $oTemplate->assign('checkbox_widget', addCheckBox('delete_' . $this->name, FALSE, SMPREF_YES, array_merge(array('id' => 'delete_' . $this->name), $this->aExtraAttribs)));
888
889//FIXME: $this->aExtraAttribs probably should only be used in one place
890 $oTemplate->assign('input_key_widget', addInput('add_' . $this->name . '_key', '', 22, 0, $this->aExtraAttribs));
891 $oTemplate->assign('input_value_widget', addInput('add_' . $this->name . '_value', '', 12, 0, $this->aExtraAttribs));
892
893 $oTemplate->assign('select_height', $height);
894
895 $oTemplate->assign('aAttribs', $this->aExtraAttribs);
896
897 $oTemplate->assign('trailing_text', $this->trailing_text);
898
899 switch ($this->layout_type) {
900 case SMOPT_EDIT_LIST_LAYOUT_SELECT:
901 return $oTemplate->fetch('edit_list_associative_widget.tpl');
902 case SMOPT_EDIT_LIST_LAYOUT_LIST:
903 return $oTemplate->fetch('edit_list_associative_widget_list_style.tpl');
904 default:
905 error_box(sprintf(_("Associative Edit List Layout Type '%s' Not Found"), $this->layout_type));
52639d23 906 }
38d93650 907
908 }
909
b6a08d2d 910 /**
911 * Creates a submit button
912 *
913 * @return string html formated submit button widget
914 *
915 */
916 function createWidget_Submit() {
917
3047e291 918 return addSubmit($this->comment, $this->name, $this->aExtraAttribs) . sm_encode_html_special_chars($this->trailing_text);
b6a08d2d 919
920 }
921
b4856b14 922 /**
923 *
924 */
cbe5423b 925 function save() {
926 $function = $this->save_function;
927 $function($this);
44ef0f47 928 }
cbe5423b 929
b4856b14 930 /**
931 *
932 */
cbe5423b 933 function changed() {
38d93650 934
935 // edit lists have a lot going on, so we'll always process them
936 //
282f8e7c 937 if ($this->type == SMOPT_TYPE_EDIT_LIST
938 || $this->type == SMOPT_TYPE_EDIT_LIST_ASSOCIATIVE)
939 return TRUE;
38d93650 940
6206f6c4 941 return ($this->value != $this->new_value);
cbe5423b 942 }
b4856b14 943} /* End of SquirrelOption class*/
cbe5423b 944
b4856b14 945/**
f2aba536 946 * Saves the option value (this is the default save function
947 * unless overridden by the user)
948 *
b4856b14 949 * @param object $option object that holds option name and new_value
950 */
cbe5423b 951function save_option($option) {
f2aba536 952
953 // Can't save the pref if we don't have the username
954 //
dac16606 955 if ( !sqgetGlobalVar('username', $username, SQ_SESSION ) ) {
dac16606 956 return;
0b97a708 957 }
f2aba536 958
ce102fcc 959 // if the widget is a selection list, make sure the new
960 // value is actually in the selection list and is not an
961 // injection attack
962 //
963 if ($option->type == SMOPT_TYPE_STRLIST
964 && !array_key_exists($option->new_value, $option->possible_values))
965 return;
966
967
968 // all other widgets except TEXTAREAs should never be allowed to have newlines
969 //
970 else if ($option->type != SMOPT_TYPE_TEXTAREA)
971 $option->new_value = str_replace(array("\r", "\n"), '', $option->new_value);
972
973
0b97a708 974 global $data_dir;
f2aba536 975
38d93650 976 // edit lists: first add new elements to list, then
977 // remove any selected ones (note that we must add
978 // before deleting because the javascript that populates
979 // the "add" textbox when selecting items in the list
980 // (for deletion))
981 //
982 if ($option->type == SMOPT_TYPE_EDIT_LIST) {
983
8eb63bb6 984 if (empty($option->possible_values)) $option->possible_values = array();
95dbbd91 985 if (!is_array($option->possible_values)) $option->possible_values = array($option->possible_values);
8eb63bb6 986
38d93650 987 // add element if given
988 //
b6a08d2d 989 if ((isset($option->use_add_widget) && $option->use_add_widget)
990 && sqGetGlobalVar('add_' . $option->name, $new_element, SQ_POST)) {
38d93650 991 $new_element = trim($new_element);
992 if (!empty($new_element)
993 && !in_array($new_element, $option->possible_values))
994 $option->possible_values[] = $new_element;
995 }
996
997 // delete selected elements if needed
998 //
de4c101c 999 if ((isset($option->use_delete_widget) && $option->use_delete_widget)
1000 && is_array($option->new_value)
38d93650 1001 && sqGetGlobalVar('delete_' . $option->name, $ignore, SQ_POST))
1002 $option->possible_values = array_diff($option->possible_values, $option->new_value);
1003
1004 // save full list (stored in "possible_values")
1005 //
1006 setPref($data_dir, $username, $option->name, serialize($option->possible_values));
1007
282f8e7c 1008 // associative edit lists are handled similar to
1009 // non-associative ones
1010 //
1011 } else if ($option->type == SMOPT_TYPE_EDIT_LIST_ASSOCIATIVE) {
1012
1013 if (empty($option->possible_values)) $option->possible_values = array();
1014 if (!is_array($option->possible_values)) $option->possible_values = array($option->possible_values);
1015
1016 // add element if given
1017 //
1018 $new_element_key = '';
1019 $new_element_value = '';
1020 $retrieve_key = sqGetGlobalVar('add_' . $option->name . '_key', $new_element_key, SQ_POST);
1021 $retrieve_value = sqGetGlobalVar('add_' . $option->name . '_value', $new_element_value, SQ_POST);
1022
1023 if ((isset($option->use_add_widget) && $option->use_add_widget)
1024 && ($retrieve_key || $retrieve_value)) {
1025 $new_element_key = trim($new_element_key);
1026 $new_element_value = trim($new_element_value);
1027 if ($option->poss_value_folders && empty($new_element_key))
1028 $new_element_value = '';
1029 if (!empty($new_element_key) || !empty($new_element_value)) {
1030 if (empty($new_element_key)) $new_element_key = '0';
1031 $option->possible_values[$new_element_key] = $new_element_value;
1032 }
1033 }
1034
1035 // delete selected elements if needed
1036 //
1037 if ((isset($option->use_delete_widget) && $option->use_delete_widget)
1038 && is_array($option->new_value)
1039 && sqGetGlobalVar('delete_' . $option->name, $ignore, SQ_POST)) {
1040
1041 if ($option->layout_type == SMOPT_EDIT_LIST_LAYOUT_SELECT) {
1042 foreach ($option->new_value as $key)
1043 unset($option->possible_values[urldecode($key)]);
1044 }
1045 else
1046 $option->possible_values = array_diff($option->possible_values, $option->new_value);
1047 }
1048
1049 // save full list (stored in "possible_values")
1050 //
1051 setPref($data_dir, $username, $option->name, serialize($option->possible_values));
1052
f2aba536 1053 // Certain option types need to be serialized because
1054 // they are not scalar
1055 //
5a42c101 1056 } else if ($option->is_multiple_valued())
f2aba536 1057 setPref($data_dir, $username, $option->name, serialize($option->new_value));
38d93650 1058
74b80a51 1059 // Checkboxes, when unchecked, don't submit anything in
1060 // the POST, so set to SMPREF_OFF if not found
1061 //
1062 else if (($option->type == SMOPT_TYPE_BOOLEAN
1063 || $option->type == SMOPT_TYPE_BOOLEAN_CHECKBOX)
1064 && empty($option->new_value))
1065 setPref($data_dir, $username, $option->name, SMPREF_OFF);
1066
2f8c79ee 1067 // For integer fields, make sure we only have digits...
1068 // We'll be nice and instead of just converting to an integer,
1069 // we'll physically remove each non-digit in the string.
1070 //
1071 else if ($option->type == SMOPT_TYPE_INTEGER) {
1072 $option->new_value = preg_replace('/[^0-9]/', '', $option->new_value);
1073 setPref($data_dir, $username, $option->name, $option->new_value);
1074 }
1075
f2aba536 1076 else
1077 setPref($data_dir, $username, $option->name, $option->new_value);
1078
b4f1a9ee 1079
1080 // if a checkbox or multi select is zeroed/cleared out, it
1081 // needs to have an empty value pushed into its "new_value" slot
1082 //
1083 if (($option->type == SMOPT_TYPE_STRLIST_MULTI
1084 || $option->type == SMOPT_TYPE_BOOLEAN_CHECKBOX)
1085 && is_null($option->new_value))
1086 $option->new_value = '';
1087
cbe5423b 1088}
1089
b4856b14 1090/**
1091 * save function that does not save
1092 * @param object $option
1093 */
cbe5423b 1094function save_option_noop($option) {
1095 /* Do nothing here... */
9962527a 1096}
44ef0f47 1097
b4856b14 1098/**
1099 * Create hidden 'optpage' input field with value set by argument
1100 * @param string $optpage identification of option page
1101 * @return string html formated hidden input field
1102 */
cbe5423b 1103function create_optpage_element($optpage) {
0177059f 1104 return addHidden('optpage', $optpage);
cbe5423b 1105}
1106
b4856b14 1107/**
1108 * Create hidden 'optmode' input field with value set by argument
1109 * @param string $optmode
1110 * @return string html formated hidden input field
1111 */
cbe5423b 1112function create_optmode_element($optmode) {
0177059f 1113 return addHidden('optmode', $optmode);
cbe5423b 1114}
1115
b4856b14 1116/**
1117 * @param array $optgrps
1118 * @param array $optvals
1119 * @return array
1120 */
cbe5423b 1121function create_option_groups($optgrps, $optvals) {
a3ec3c91 1122 /* Build a simple array with which to start. */
1123 $result = array();
1124
bbcafebd 1125 /* Create option group for each option group name. */
1126 foreach ($optgrps as $grpkey => $grpname) {
1127 $result[$grpkey] = array();
1128 $result[$grpkey]['name'] = $grpname;
1129 $result[$grpkey]['options'] = array();
1130 }
1131
a3ec3c91 1132 /* Create a new SquirrelOption for each set of option values. */
bbcafebd 1133 foreach ($optvals as $grpkey => $grpopts) {
1134 foreach ($grpopts as $optset) {
28520c87 1135 /* Create a new option with all values given. */
1136 $next_option = new SquirrelOption(
d789daf0 1137 $optset,
7390e240 1138 $optset['name'],
1139 $optset['caption'],
1140 $optset['type'],
1141 (isset($optset['refresh']) ? $optset['refresh'] : SMOPT_REFRESH_NONE),
1142 (isset($optset['initial_value']) ? $optset['initial_value'] : ''),
1143 (isset($optset['posvals']) ? $optset['posvals'] : ''),
1144 (isset($optset['htmlencoded']) ? $optset['htmlencoded'] : false)
1145 );
bbcafebd 1146
e40b0e8e 1147 /* If provided, set if the caption is allowed to wrap for this option. */
1148 if (isset($optset['caption_wrap'])) {
1149 $next_option->setCaptionWrap($optset['caption_wrap']);
1150 }
1151
bbcafebd 1152 /* If provided, set the size for this option. */
1153 if (isset($optset['size'])) {
1154 $next_option->setSize($optset['size']);
1155 }
1156
361d6e1b 1157 /* If provided, set the trailing_text for this option. */
1158 if (isset($optset['trailing_text'])) {
1159 $next_option->setTrailingText($optset['trailing_text']);
1160 }
1161
5b277d00 1162 /* If provided, set the yes_text for this option. */
1163 if (isset($optset['yes_text'])) {
1164 $next_option->setYesText($optset['yes_text']);
1165 }
1166
1167 /* If provided, set the no_text for this option. */
1168 if (isset($optset['no_text'])) {
1169 $next_option->setNoText($optset['no_text']);
1170 }
1171
282f8e7c 1172 /* If provided, set the poss_value_folders value for this option. */
1173 if (isset($optset['poss_value_folders'])) {
1174 $next_option->setPossValueFolders($optset['poss_value_folders']);
1175 }
1176
52639d23 1177 /* If provided, set the layout type for this option. */
1178 if (isset($optset['layout_type'])) {
1179 $next_option->setLayoutType($optset['layout_type']);
1180 }
1181
b6a08d2d 1182 /* If provided, set the use_add_widget value for this option. */
1183 if (isset($optset['use_add_widget'])) {
1184 $next_option->setUseAddWidget($optset['use_add_widget']);
1185 }
1186
de4c101c 1187 /* If provided, set the use_delete_widget value for this option. */
1188 if (isset($optset['use_delete_widget'])) {
1189 $next_option->setUseDeleteWidget($optset['use_delete_widget']);
1190 }
1191
bbcafebd 1192 /* If provided, set the comment for this option. */
1193 if (isset($optset['comment'])) {
1194 $next_option->setComment($optset['comment']);
1195 }
1196
cbe5423b 1197 /* If provided, set the save function for this option. */
1198 if (isset($optset['save'])) {
1199 $next_option->setSaveFunction($optset['save']);
1200 }
1201
0177059f 1202 /* If provided, set the extra attributes for this option. */
1203 if (isset($optset['extra_attributes'])) {
1204 $next_option->setExtraAttributes($optset['extra_attributes']);
cbe5423b 1205 }
1206
6ae9e729 1207 /* If provided, set the "post script" for this option. */
1208 if (isset($optset['post_script'])) {
1209 $next_option->setPostScript($optset['post_script']);
1210 }
1211
99ecf044 1212 /* If provided, set the folder_filter for this option. */
1213 if (isset($optset['folder_filter'])) {
1214 $next_option->setFolderFilter($optset['folder_filter']);
1215 }
1216
bbcafebd 1217 /* Add this option to the option array. */
1218 $result[$grpkey]['options'][] = $next_option;
a3ec3c91 1219 }
1220 }
1221
1222 /* Return our resulting array. */
1223 return ($result);
1224}
1225