386 lines
16 KiB
PHP
386 lines
16 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Class for select box controls.
|
|
*
|
|
* @author Stefan Gabos <contact@stefangabos.ro>
|
|
* @copyright (c) 2006 - 2016 Stefan Gabos
|
|
* @package Controls
|
|
*/
|
|
class Zebra_Form_Select extends Zebra_Form_Control
|
|
{
|
|
|
|
/**
|
|
* Adds an <select> control to the form.
|
|
*
|
|
* <b>Do not instantiate this class directly! Use the {@link Zebra_Form::add() add()} method instead!</b>
|
|
*
|
|
* By default, unless the <b>multiple</b> attribute is set, the control will have a default first option added
|
|
* automatically inviting users to select one of the available options. Default value for English is
|
|
* "<i>- select -</i>" taken from the language file - see the {@link Zebra_Form::language() language()}
|
|
* method. If you don't want it or want to set it at runtime, set the <i>overwrite</i> argument to TRUE when calling
|
|
* the {@link add_options()} method.
|
|
*
|
|
* <code>
|
|
* // create a new form
|
|
* $form = new Zebra_Form('my_form');
|
|
*
|
|
* // single-option select box
|
|
* $obj = $form->add('select', 'my_select');
|
|
*
|
|
* // add selectable values with default indexes
|
|
* // values will be "0", "1" and "2", respectively
|
|
* // a default first value, "- select -" (language dependent) will also be added
|
|
* $obj->add_options(array(
|
|
* 'Value 1',
|
|
* 'Value 2',
|
|
* 'Value 3'
|
|
* ));
|
|
*
|
|
* // single-option select box
|
|
* $obj = $form->add('select', 'my_select2');
|
|
*
|
|
* // add selectable values with specific indexes
|
|
* // values will be "v1", "v2" and "v3", respectively
|
|
* // a default first value, "- select -" (language dependent) will also be added
|
|
* $obj->add_options(array(
|
|
* 'v1' => 'Value 1',
|
|
* 'v2' => 'Value 2',
|
|
* 'v3' => 'Value 3'
|
|
* ));
|
|
*
|
|
* // single-option select box with the second value selected
|
|
* $obj = $form->add('select', 'my_select3', 'v2');
|
|
*
|
|
* // add selectable values with specific indexes
|
|
* // values will be "v1", "v2" and "v3", respectively
|
|
* // also, overwrite the language-specific default first value (notice the boolean TRUE at the end)
|
|
* $obj->add_options(array(
|
|
* '' => '- select a value -',
|
|
* 'v1' => 'Value 1',
|
|
* 'v2' => 'Value 2',
|
|
* 'v3' => 'Value 3'
|
|
* ), true);
|
|
*
|
|
* // multi-option select box with the first two options selected
|
|
* $obj = $form->add('select', 'my_select4[]', array('v1', 'v2'), array('multiple' => 'multiple'));
|
|
*
|
|
* // add selectable values with specific indexes
|
|
* // values will be "v1", "v2" and "v3", respectively
|
|
* $obj->add_options(array(
|
|
* 'v1' => 'Value 1',
|
|
* 'v2' => 'Value 2',
|
|
* 'v3' => 'Value 3'
|
|
* ));
|
|
*
|
|
* // don't forget to always call this method before rendering the form
|
|
* if ($form->validate()) {
|
|
* // put code here
|
|
* }
|
|
*
|
|
* // output the form using an automatically generated template
|
|
* $form->render();
|
|
* </code>
|
|
*
|
|
* <samp>By default, for checkboxes, radio buttons and select boxes, the library will prevent the submission of other
|
|
* values than those declared when creating the form, by triggering the error: "SPAM attempt detected!". Therefore,
|
|
* if you plan on adding/removing values dynamically, from JavaScript, you will have to call the
|
|
* {@link Zebra_Form_Control::disable_spam_filter() disable_spam_filter()} method to prevent that from happening!</samp>
|
|
*
|
|
* @param string $id Unique name to identify the control in the form.
|
|
*
|
|
* The control's <b>name</b> attribute will be as specified by the <i>$id</i>
|
|
* argument.<br>
|
|
* The <b>id</b> attribute will be as specified by the <i>$id</i> argument but with
|
|
* square brackets trimmed off (if any).
|
|
*
|
|
* This is the name to be used when referring to the control's value in the
|
|
* POST/GET superglobals, after the form is submitted.
|
|
*
|
|
* This is also the name of the variable (again, with square brackets trimmed off
|
|
* if it's the case) to be used in the template file, containing the generated HTML
|
|
* for the control.
|
|
*
|
|
* <code>
|
|
* // in a template file, in order to print the generated HTML
|
|
* // for a control named "my_select", one would use:
|
|
* echo $my_select;
|
|
* </code>
|
|
*
|
|
* @param mixed $default (Optional) Default selected option.
|
|
*
|
|
* This argument can also be an array in case the <b>multiple</b> attribute is set
|
|
* and multiple options need to be preselected by default.
|
|
*
|
|
* @param array $attributes (Optional) An array of attributes valid for
|
|
* {@link http://www.w3.org/TR/REC-html40/interact/forms.html#edef-SELECT select}
|
|
* controls (multiple, readonly, style, etc)
|
|
*
|
|
* Must be specified as an associative array, in the form of <i>attribute => value</i>.
|
|
* <code>
|
|
* // setting the "multiple" attribute
|
|
* $obj = $form->add(
|
|
* 'select',
|
|
* 'my_select',
|
|
* '',
|
|
* array(
|
|
* 'multiple' => 'multiple'
|
|
* )
|
|
* );
|
|
* </code>
|
|
*
|
|
* <b>Special attribute:</b>
|
|
*
|
|
* When setting the special attribute <b>other</b> to <b>true</b>, a
|
|
* {@link Zebra_Form_Text textbox} control will be automatically created having the
|
|
* name <i>[id]_other</i> where [id] is the select control's <b>id</b> attribute.
|
|
* The text box will be hidden until the user selects the automatically added
|
|
* <i>Other...</i> option (language dependent) from the selectable options. The
|
|
* option's value will be <b>other</b>. If the template is not automatically
|
|
* generated you will have to manually add the automatically generated control to
|
|
* the template.
|
|
*
|
|
* See {@link Zebra_Form_Control::set_attributes() set_attributes()} on how to set
|
|
* attributes, other than through the constructor.
|
|
*
|
|
* The following attributes are automatically set when the control is created and
|
|
* should not be altered manually:<br>
|
|
*
|
|
* <b>id</b>, <b>name</b>
|
|
*
|
|
* @param string $default_other The default value in the "other" field (if the "other" attribute is set to true,
|
|
* see above)
|
|
*
|
|
* @return void
|
|
*/
|
|
function __construct($id, $default = '', $attributes = '', $default_other = '')
|
|
{
|
|
|
|
// call the constructor of the parent class
|
|
parent::__construct();
|
|
|
|
// set the private attributes of this control
|
|
// these attributes are private for this control and are for internal use only
|
|
// and will not be rendered by the _render_attributes() method
|
|
$this->private_attributes = array(
|
|
|
|
'default_other',
|
|
'disable_spam_filter',
|
|
'disable_xss_filters',
|
|
'locked',
|
|
'options',
|
|
'other',
|
|
'type',
|
|
'value',
|
|
|
|
);
|
|
|
|
// set the default attributes for the textarea control
|
|
// put them in the order you'd like them rendered
|
|
$this->set_attributes(
|
|
|
|
array(
|
|
|
|
'name' => $id,
|
|
'id' => str_replace(array('[', ']'), '', $id),
|
|
'class' => 'control',
|
|
'options' => array(),
|
|
'type' => 'select',
|
|
'value' => $default,
|
|
'default_other' => $default_other,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
// if "class" is amongst user specified attributes
|
|
if (is_array($attributes) && isset($attributes['class'])) {
|
|
|
|
// we need to set the "class" attribute like this, so it doesn't overwrite previous values
|
|
$this->set_attributes(array('class' => $attributes['class']), false);
|
|
|
|
// make sure we don't set it again below
|
|
unset($attributes['class']);
|
|
|
|
}
|
|
|
|
// sets user specified attributes for the control
|
|
$this->set_attributes($attributes);
|
|
|
|
}
|
|
|
|
/**
|
|
* Adds options to the select box control
|
|
*
|
|
* <b>If the "multiple" attribute is not set, the first option will be always considered as the "nothing is selected"
|
|
* state of the control!</b>
|
|
*
|
|
* @param array $options An associative array of options where the key is the value of the option and the
|
|
* value is the actual text to be displayed for the option.
|
|
*
|
|
* <b>Option groups</b> can be set by giving an array of associative arrays as argument:
|
|
*
|
|
* <code>
|
|
* // add as groups:
|
|
* $obj->add_options(array(
|
|
* 'group' => array('option 1', 'option 2')
|
|
* ));
|
|
* </code>
|
|
*
|
|
* @param boolean $overwrite (Optional) By default, succesive calls of this method will appended the options
|
|
* given as arguments to the already existing options.
|
|
*
|
|
* Setting this argument to TRUE will instead overwrite the previously existing options.
|
|
*
|
|
* Default is FALSE
|
|
*
|
|
* @return void
|
|
*/
|
|
function add_options($options, $overwrite = false)
|
|
{
|
|
|
|
// continue only if parameter is an array
|
|
if (is_array($options)) {
|
|
|
|
// get some properties of the select control
|
|
$attributes = $this->get_attributes(array('options', 'multiple'));
|
|
|
|
// if there are no options so far AND
|
|
// we're not overwriting existing options AND
|
|
// the "multiple" attribute is not set
|
|
if (empty($attributes['options']) && $overwrite === false && !isset($attributes['multiple']))
|
|
|
|
// add the default value
|
|
// we'll replace the value with the appropriate language
|
|
$options = array('' => $this->form_properties['language']['select']) + $options;
|
|
|
|
// set the options attribute of the control
|
|
$this->set_attributes(
|
|
|
|
array(
|
|
|
|
'options' => ($overwrite ? $options : $attributes['options'] + $options)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
// if options are not specified as an array
|
|
} else {
|
|
|
|
// trigger an error message
|
|
_zebra_form_show_error('
|
|
Selectable values for the <strong>' . $this->attributes['id'] . '</strong> control must be specified as
|
|
an array
|
|
');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Generates the control's HTML code.
|
|
*
|
|
* <i>This method is automatically called by the {@link Zebra_Form::render() render()} method!</i>
|
|
*
|
|
* @return string The control's HTML code
|
|
*/
|
|
function toHTML()
|
|
{
|
|
|
|
// get the options of the select control
|
|
$attributes = $this->get_attributes(array('options', 'value', 'multiple', 'other'));
|
|
|
|
// if select box is not "multi-select" and the "other" attribute is set
|
|
if (!isset($attributes['multiple']) && isset($attributes['other']))
|
|
|
|
// add an extra options to the already existing ones
|
|
$attributes['options'] += array('other' => $this->form_properties['language']['other']);
|
|
|
|
// if the default value, as added when instantiating the object is still there
|
|
// or if no options were specified
|
|
if (($key = array_search('#replace-with-language#', $attributes['options'])) !== false || empty($attributes['options']))
|
|
|
|
// put the label from the language file
|
|
$attributes['options'][$key] = $this->form_properties['language']['select'];
|
|
|
|
// use a private, recursive method to generate the select's content
|
|
$optContent = $this->_generate($attributes['options'], $attributes['value']);
|
|
|
|
// return generated HTML
|
|
return '<select '. $this->_render_attributes() . '>' . $optContent . '</select>';
|
|
|
|
}
|
|
|
|
/**
|
|
* Takes the options array and recursively generates options and optiongroups
|
|
*
|
|
* @return string Resulted HTML code
|
|
*
|
|
* @access private
|
|
*/
|
|
private function _generate(&$options, &$selected, $level = 0)
|
|
{
|
|
|
|
$content = '';
|
|
|
|
// character(s) used for indenting levels
|
|
$indent = ' ';
|
|
|
|
// iterate through the available options
|
|
foreach ($options as $value => $caption) {
|
|
|
|
// if option has child options
|
|
if (is_array($caption)) {
|
|
|
|
// create a dummy option group (for valid HTML/XHTML we are not allowed to create nested option groups
|
|
// and also empty optiongroups are not allowed)
|
|
// BUT because in IE7 the "disabled" attribute is not supported and in all versions of IE these
|
|
// can't be styled, we will remove them from JavaScript
|
|
// having a dummy option in them (the option is disabled and, from CSS, rendered invisible)
|
|
$content .= '
|
|
<optgroup label="' . str_repeat($indent, $level) . $value . '">
|
|
<option disabled="disabled" class="dummy"></option>
|
|
</optgroup>
|
|
';
|
|
|
|
// call the method recursively to generate the output for the children options
|
|
$content .= $this->_generate($caption, $selected, $level + 1);
|
|
|
|
// if entry is a standard option
|
|
} else {
|
|
|
|
// create the appropriate code
|
|
$content .= '<option value="' . $value . '"' .
|
|
|
|
// if anything was selected
|
|
($selected !== '' && $value !== '' &&
|
|
|
|
(
|
|
|
|
// and the current option is selected
|
|
(is_array($selected) && in_array($value, $selected)) ||
|
|
|
|
(!is_array($selected) && (string)$value === (string)$selected)
|
|
|
|
// set the appropriate attribute
|
|
) ? ' selected="selected"' : ''
|
|
|
|
) . '>' .
|
|
|
|
// indent appropriately
|
|
str_repeat($indent, $level) . $caption . '</option>';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// return generated content
|
|
return $content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
?>
|