#n2:checked .......label.n1 - How to write a selector for form?

<input id="n1" type="radio" name="p01-contact_fields[5]" value=" &#1052;&#1091;&#1078;&#1095;&#1080;&#1085;&#1072;">
                    <label for="n1" class="n1"> Man</label>
                    <input id="n2" type="radio" name="p01-contact_fields[5]" value=" &#1046;&#1077;&#1085;&#1097;&#1080;&#1085;&#1072;">
                    <label for="n2" class="n2"> Woman</label></div>

For input id=“n1” is:

#n1:checked ~ label.n2

How to write a selector for id=“n2”

#n2:checked …label.n1 {
}

Hi,

Is this a follow on from this thread to which you didn’t reply?

It seems though that you are asking a similar but different question and it it looks like you want to select a parent element when a child is clicked and this cannot be done in CSS (the parent selector has been on the wishlist for years but never comes to fruition).

You can achieve something similar in your example by moving the inputs together andf then absolutely positioning them into position to ,ook as though they are next to the labels.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style>
.wrap { position:relative; }
#n2, .n2 {
	position:absolute;
	left:75px;
}
.n2 { left:100px }
 #n1:checked ~ label.n2, #n2:checked ~ label.n1 {
opacity:0.3
}
</style>
</head>

<body>
<div class="wrap">
		<input id="n1" type="radio" name="p01-contact_fields[5]" value=" &#1052;&#1091;&#1078;&#1095;&#1080;&#1085;&#1072;">
		<input id="n2" type="radio" name="p01-contact_fields[5]" value=" &#1046;&#1077;&#1085;&#1097;&#1080;&#1085;&#1072;">
		<label for="n1" class="n1"> Man</label>
		<label for="n2" class="n2"> Woman</label>
</div>
</body>
</html>

There is a way to maintain the flow of the document but would involve hiding the actual radio boxes off screen and instead using background images in the label instead to represent them. As long as the input is associated with the label it doesn’t really matter where it sits in the html and clicking the label will activate the input anyway.

case 'radio' :
			$html .= '<div class="radio-selector" id="rselect' . $id . '">';
                foreach($this->value as $i => $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : ' Default';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? ' checked' : '';
					
                    $html .= '
                    <input id="' . $id . '_option' . $i . '" type="radio" ';
                    $html .= 'name="' . $name . '" value="' . $value . '"';
                    $html .= $disabled . $selected . ' />';
					$html .= '
                    <label for="' . $id . '_option' . $i . '" ';
					$html .= '
                    class="' . $id . '_option' . $i . '" ';
                    $html .= $disabled . $selected . ' />' . $value . '</label>';
					
                }
				$html .= '</div>';
                break;

How to withdraw this code

Thread moved to JS forum.

Please clarify how the code above refers to the original question and I’m sure one of the JS experts will help.

This php code that displays a form in the cms getsimple

case 'radio' :
			$html .= '<div class="radio-selector" id="rselect' . $id . '">';
                foreach($this->value as $i => $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : ' Default';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? ' checked' : '';
					
                    $html .= '
                    <input id="' . $id . '_option' . $i . '" type="radio" ';
                    $html .= 'name="' . $name . '" value="' . $value . '"';
                    $html .= $disabled . $selected . ' />';
					$html .= '
                    <label for="' . $id . '_option' . $i . '" ';
					$html .= '
                    class="' . $id . '_option' . $i . '" ';
                    $html .= $disabled . $selected . ' />' . $value . '</label>';
					
                }
				$html .= '</div>';
                break;

Now he brings so form

<input id="n1" type="radio" name="p01-contact_fields[5]" value=" &#1052;&#1091;&#1078;&#1095;&#1080;&#1085;&#1072;">
                    <label for="n1" class="n1"> Man</label>
                    <input id="n2" type="radio" name="p01-contact_fields[5]" value=" &#1046;&#1077;&#1085;&#1097;&#1080;&#1085;&#1072;">
                    <label for="n2" class="n2"> Woman</label></div>

And it is necessary that all the label after all input

<input id="n1" type="radio" name="p01-contact_fields[5]" value=" &#1052;&#1091;&#1078;&#1095;&#1080;&#1085;&#1072;">
		<input id="n2" type="radio" name="p01-contact_fields[5]" value=" &#1046;&#1077;&#1085;&#1097;&#1080;&#1085;&#1072;">
		<label for="n1" class="n1"> Man</label>
		<label for="n2" class="n2"> Woman</label>

All php code of file

&lt;?php
/**
 * p01-contact - A simple contact forms manager
 *
 * @link http://nliautaud.fr/wiki/travaux/getsimple_p01-contact Documentation
 * @link http://get-simple.info/extend/plugin/p01-contact/35 Latest Version
 * @author Nicolas Liautaud &lt;contact@nliautaud.fr&gt;
 * @package p01-contact
 * @version 0.9.1
 */
if(session_id()=='') session_start();

class P01contact
{
    public $version;
    public $default_email;
    public $default_lang;
    public $securimage_url;
    private $forms;

    public function __construct()
    {
        $this-&gt;version = '0.9.1';
        $this-&gt;forms = array();
        $dir = dirname(__FILE__);
        define('LANGPATH', $dir . '/lang/');
        define('CONFIGPATH', $dir . '/config.php');
        define('CAPTCHAPATH', $dir . '/captcha/');

        define('DOCURL', 'http://nliautaud.fr/wiki/travaux/p01-contact');
        define('DOWNURL', 'http://get-simple.info/extend/plugin/p01-contact/35');
        define('FORUMURL', 'http://get-simple.info/forum/topic/1108');
        define('VERSIONURL', 'http://get-simple.info/api/extend/?id=35');
    }

    /**
     * Parse a string to replace tags by forms
     *
     * Find tags, create forms structures, check POST and modify string.
     * @param string $contents the string to parse
     * @return string the modified string
     */
    public function parse($contents)
    {
        $pattern = '`(?<!<code>)\\(%\\s*contact\\s*(.*)\\s*%\\)`';
        preg_match_all($pattern, $contents, $tags, PREG_SET_ORDER);
        $ids = array();

        // create forms structures from TAG
        foreach($tags as $tag) {
            $id = $this-&gt;new_form_id();
            $form = $this-&gt;parse_tag($id, $tag[1]);
            $this-&gt;forms[$id] = $form;
            $ids[] = $id; // forms manipulated by this parsing session
        }
        // modify forms structures from POST, send mail
        if(!empty($_POST['p01-contact_form'])) {
            $this-&gt;post();
        }
        // replace tags by forms
        foreach($ids as $id) {
            $contents = preg_replace($pattern, $this-&gt;forms[$id]-&gt;html(), $contents, 1);
        }
        return $contents;
    }

    private function format($str)
    {
        $str = trim(preg_replace(
            array('`&nbsp;`','`&quot;`'),
            array(' ','"'),
            $str)
        );
        return $str;
    }
    /**
     * Parse a tag to create form structure
     *
     * Find emails and parameters, create and setup form object.
     * @param int $id the form id
     * @param string $tag the tag to parse
     * @return P01contact_form the form object
     */
    private function parse_tag($id, $tag)
    {

        $form = new P01contact_form($this, $id);
        $tag = $this-&gt;format($tag);

        $param_pattern = '`[,:]\\s*([^ ,"=!]+)(!)?\\s*("([^"]*)")?\\s*((=>|=)?\\s*([^,]*))?\\s*`';
        $targets_pattern = '`[,:]\\s*([_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,3}))`i';
        $values_pattern = '`(?:^|\\|)\\s*(?:"([^"]+)")?\\s*([^| ]+)?`';

        // parse emails
        preg_match_all($targets_pattern, $tag, $targets);
        $targets = array_unique($targets[1]);
        // add targets
        if(empty($targets)) {
            $default_email = $this-&gt;get_default_email();
            if($default_email)
                $form-&gt;add_target($default_email);
        } else {
            $form-&gt;set_targets($targets);
        }
        // delete them from tag
        $rest = preg_replace($targets_pattern, '', $tag);
        $rest = $this-&gt;format($rest);
        // parse parameters
        preg_match_all($param_pattern, $rest, $params, PREG_SET_ORDER);
        if(empty($params)) {
            $default = $this-&gt;settings('default_params');
            $default = $this-&gt;format($default);
            preg_match_all($param_pattern, ': ' . $default, $params, PREG_SET_ORDER);
        }
        // add fields
        foreach($params as $id =&gt; $param) {
            $field = new P01contact_field($form, $id, $param[1]);
            $field-&gt;set_title($param[4]);

            if($param[1] == 'select'
            || $param[1] == 'radio'
            || $param[1] == 'checkbox') {
                // fields with multiples values
                preg_match_all($values_pattern, $param[7], $values, PREG_SET_ORDER);
                $values = unset_r($values, 0);
                $field-&gt;set_value($values);
            }
            elseif($param[1] == 'askcopy') {
                // create checkbox-like structure
                $field-&gt;set_value(array(array(1 =&gt; $this-&gt;lang('askcopy'))));
            }
            elseif($param[1] == 'password') {
                // password value is required value
                $field-&gt;set_required($param[7]);
            }
            else $field-&gt;set_value($param[7]);


            if($param[1] != 'password')
                $field-&gt;set_required($param[2] == '!' ? True : False);
            $field-&gt;set_locked($param[6] == '=&gt;' ? True : False);
            $form-&gt;add_field($field);
        }

        return $form;
    }

    /**
     * Update POSTed form and try to send mail
     *
     * Check posted data, update form data,
     * define fields errors and form status.
     * At least, if there is no errors, try to send mail.
     */
    private function post()
    {
        // check posted data and update form data
        $form_id = $_POST['p01-contact_form']['id'];
        if(isset($this-&gt;forms[$form_id]))
        {
            $form = $this-&gt;forms[$form_id];
            foreach($this-&gt;format_data($_POST['p01-contact_fields']) as $field_id =&gt; $field_post)
            {
                $field = $form-&gt;get_field($field_id);

                // for multiple-values fields, posted value define selection
                $value = $field-&gt;get_value();
                if(is_array($value)) {
                    // selections need to be an array
                    if(!is_array($field_post)) $selections = array($field_post);
                    else $selections = $field_post;
                    // reset value selection
                    foreach($value as $key =&gt; $val) {
                        $value[$key][2] = '';
                    }
                    // set value selection from POST
                    foreach($selections as $selection) {
                        foreach($value as $key =&gt; $val) {
                            if(trim($val[1]) == trim($selection))
                                $value[$key][2] = 'selected';
                        }
                    }
                    $field-&gt;set_value($value);
                }
                // for unique value fields, posted value define value
                else $field-&gt;set_value($field_post);

                $check = $field-&gt;check_content();
                $field-&gt;set_error($check);
                if($check) $errors = True;
            }
            // SECURITY : check tokens
            if(!$this-&gt;check_token()) {
                $form-&gt;set_status('token');
                $this-&gt;set_token();
                $form-&gt;reset();
            }
            // try to send mail
            elseif(!isset($errors)) {
                if($this-&gt;settings('enable') === False) {
                    $form-&gt;set_status('disable');
                } elseif($form-&gt;count_targets() == 0) {
                    $form-&gt;set_status('target');
                } else {
                    $form-&gt;send_mail();
                    $this-&gt;set_token();
                    $form-&gt;reset();
                }
            }
         }
    }

    /**
     * Return next accessible form ID
     * @param string $key the setting key
     * @return mixed the setting value
     */
    private function new_form_id()
    {
        end($this-&gt;forms);
        $id = key($this-&gt;forms) + 1;
        reset($this-&gt;forms);
        return $id;
    }

    /**
     * Print POST and p01-contact content.
     */
    public function debug()
    {
        ini_set('display_errors', 'on');
        error_reporting(E_ALL);
        echo'&lt;h2 style="color:#c33"&gt;p01-contact debug&lt;/h2&gt;';
        if(!empty($_POST)) {
            echo'&lt;h3&gt;$_POST :&lt;/h3&gt;';
            echo'&lt;pre&gt;';
            @print_r($_POST);
            echo'&lt;/pre&gt;';
        }
        echo'&lt;h3&gt;$p01contact :&lt;/h3&gt;';
        echo'&lt;pre&gt;';
        print_r($this);
        echo'&lt;/pre&gt;';
    }

    /**
     * Return a setting value from config file
     * @param string $key the setting key
     * @return mixed the setting value
     */
    public function settings($key)
    {
        require CONFIGPATH;
        if(isset($p01contact_settings[$key]))
            return $p01contact_settings[$key];
    }

    /**
     * Format array values
     *
     * For aesthetic and security, and recursive.
     * @param array $array
     * @return array
     */
    private function format_data($array)
    {
        foreach($array as $key =&gt; $val) {
            if(is_array($val)) $this-&gt;format_data($array[$key]);
            else {
                $tmp = stripslashes($val);
                $tmp = htmlentities($tmp, ENT_QUOTES, 'UTF-8');
                $array[$key] = $tmp;
            }
        }
        return $array;
    }

    /**
     * Return a traduction of the keyword
     *
     * Manage languages between requested langs and existing traductions.
     * @param string $key the keyword
     * @return string
     */
    public function lang($key)
    {
        global $p01contact_lang;

        $lang = $this-&gt;settings('lang');
        $lang = empty($lang) ? $this-&gt;default_lang : $lang;

        $path = LANGPATH . $lang . '.php';

        $lang = file_exists($path) ? $lang : 'en';

        include_once $path;

        if(isset($p01contact_lang[$key])) {
            return $p01contact_lang[$key];
        } else {
            return ucfirst($key);
        }
    }
    /**
     * Return list of existing langs from lang/langs.php
     * @return array
     */
    private function langs()
    {
        require LANGPATH . '/langs.php';
        return $p01contact_langs;
    }

    /**
     * Return the last version of p01-contact in GS
     * @return string
     */
    private function last_version()
    {
        $apiback = file_get_contents(VERSIONURL);
        $response = json_decode($apiback);
        if ($response-&gt;status == 'successful') {
            return $response-&gt;version;
        }
    }
    /**
     * Check if a new version exists. Return version number if exists, or False.
     * @return mixed
     */
    private function exists_new_version()
    {
        $actual = explode('.', $this-&gt;version);
        $last = $this-&gt;last_version();
        $last_r = explode('.', $last);
        foreach($actual as $key =&gt; $val)
            if(isset($last_r[$key])
            && $val &lt; $last_r[$key])
                return $last;
        return False;
    }

    /**
     * Save settings if necessary and display configuration panel content
     * Parse and replace values in php config file by POST values.
     */
    public function panel()
    {
        if(isset($_POST['p01-contact']['settings'])) {
            $data = $this-&gt;format_data($_POST['p01-contact']['settings']);
            if($content = file_get_contents(CONFIGPATH)) {

                $enable  = isset($data['enable']) ? 'True' : 'False';
                $content = preg_replace("`('enable' => )(True|False)`", "\\\\1$enable", $content);
                $debug   = isset($data['debug']) ? 'True' : 'False';
                $content = preg_replace("`('debug' => )(True|False)`", "\\\\1$debug", $content);
                $content = preg_replace("`('lang' => ')[a-z]*'`", "\\\\1{$data['lang']}'", $content);
                $content = preg_replace("`('default_params' => ')[^']*'`", "\\\\1{$data['default_params']}'", $content);
                $content = preg_replace("`('default_email' => ')[^']*'`", "\\\\1{$data['default_email']}'", $content);
                $content = preg_replace("`'message_len' => [0-9]+`", "'message_len' =&gt; {$data['message_len']}", $content);

                foreach($data['checklist'] as $key =&gt; $val) {
                    $content = preg_replace("`('checklist_$key' => ')[^']*'`", "\\\\1$val'", $content);
                }
                if(file_exists(CONFIGPATH)
                && $file = fopen(CONFIGPATH, 'w')) {
                    fwrite($file, $content);
                    fclose($file);

                    global $p01contact_settings;
                    require(CONFIGPATH);
                    $updated = '&lt;div class="updated"&gt;' . $this-&gt;lang('config_updated') . '&lt;/div&gt;';
                } else {
                    $error = $this-&gt;lang('config_error_modify');
                }
            } else {
                $error = $this-&gt;lang('config_error_open');
            }
        }
        if(isset($updated)) echo $updated;
        elseif(isset($errors)) {
            echo '&lt;div class="error"&gt;' . $error . '&lt;pre&gt;' . CONFIGPATH . '&lt;/pre&gt;&lt;/div&gt;';
        }
        echo $this-&gt;panel_content();
    }

    /**
     * Return configuration panel content
     *
     * Display informations, parse config file and display settings form.
     * @return string
     */
    private function panel_content()
    {
        global $p01contact_settings;
        $config_file = file_get_contents(CONFIGPATH, true); //true: use_include_path
        $pattern = '`/\\*[^*]*\\* ([^*]*).*\\* ([^*]*)[^*]*(\\* ([^*]*))?\\*/`';
        preg_match_all($pattern, $config_file, $descs);

        $c = '&lt;h2&gt;' . $this-&gt;lang('config_title') . '&lt;/h2&gt;';

        //new release
        if($newversion = $this-&gt;exists_new_version()) {
            $c.= '&lt;div class="updated"&gt;' . $this-&gt;lang('new_release');
            $c.= '&lt;br /&gt;&lt;a href="' . DOWNURL . '"&gt;';
            $c.= $this-&gt;lang('download') . ' (' . $newversion . ')&lt;/a&gt;&lt;/div&gt;';
        }
        //links
        $c.= '&lt;p&gt;&lt;a href="' . DOCURL . '"&gt;' . $this-&gt;lang('doc') . '&lt;/a&gt;';
        $c.= ' - &lt;a href="' . FORUMURL . '"&gt;' . $this-&gt;lang('forum') . '&lt;/a&gt;&lt;/p&gt;';

        $c.= '&lt;form action="" method="post"&gt;&lt;table&gt;';

        //enable
        $c.= '&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;' . $this-&gt;lang('enable') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('enable_sub') . '&lt;/i&gt;&lt;/td&gt;';
        $c.= '&lt;td&gt;&lt;input type="checkbox" name="p01-contact[settings][enable]" ';
        $c.= $this-&gt;settings('enable') ? 'checked="checked" ' : '';
        $c.= '/&gt;&lt;/td&gt;&lt;/tr&gt;';

        //default email
        $c.= '&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;';
        $c.= $this-&gt;lang('default_email') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('default_email_sub') . ' ';
        $c.= ($this-&gt;default_email ? $this-&gt;default_email : '"not set"') . '&lt;/i&gt;&lt;/td&gt;&lt;td&gt;';
        $c.= '&lt;input type="text" name="p01-contact[settings][default_email]" ';
        $settings_email = $this-&gt;settings('default_email');
        $c.= 'value="' . $settings_email . '" /&gt;';
        $c.= '&lt;/td&gt;&lt;/tr&gt;';

        // language
        $c.= '&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;' . $this-&gt;lang('lang') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('lang_sub') . ' ' . $this-&gt;default_lang . '&lt;/i&gt;&lt;/td&gt;';
        $c.= '&lt;/td&gt;&lt;td&gt;&lt;select name="p01-contact[settings][lang]"&gt;';
        $lang = $this-&gt;settings('lang');
        $c.= '&lt;option value=""' . ($lang == ''?' selected="selected" ':'') . '&gt;Default&lt;/option&gt;';
        foreach($this-&gt;langs() as $iso =&gt; $name) {
            $c.= '&lt;option value="' . $iso . '" ';
            if($lang == $iso) $c.= 'selected="selected" ';
            $c.= '/&gt;' . $name . '&lt;/option&gt;';
        }
        $c.= '&lt;/select&gt;&lt;/td&gt;&lt;/tr&gt;';

        //message length
        $c.= '&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;' . $this-&gt;lang('message_len') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('message_len_sub') . '&lt;/i&gt;&lt;/td&gt;';
        $c.= '&lt;td&gt;&lt;input type="text" name="p01-contact[settings][message_len]" size=3 maxlength=3 ';
        $c.= 'value="' . $this-&gt;settings('message_len').'" /&gt;&lt;/td&gt;&lt;/tr&gt;';

        // default parameters
        $c.= '&lt;tr&gt;&lt;td colspan="2"&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;';
        $c.= $this-&gt;lang('default_params') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('default_params_sub') . '&lt;/i&gt;&lt;br /&gt;';
        $c.= '&lt;textarea name="p01-contact[settings][default_params]" style="width:100%;height:40px"&gt;';
        $c.= $this-&gt;settings('default_params');
        $c.= '&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;';

        //checklists
        $c.= '&lt;tr&gt;&lt;td colspan="2"&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;';
        $c.= $this-&gt;lang('checklists') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('checklists_sub') . '&lt;/i&gt;';
        $fields = array(
            'general_fields' =&gt; array('text','textarea'), 'special_fields' =&gt;
            array('name','email','address','phone','website','subject','message'));
        foreach($fields as $type =&gt; $f)
            foreach($f as $id=&gt;$field) {
                if(!$id) $c.= '&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;' . $this-&gt;lang($type) . ' :&lt;/b&gt;&lt;/p&gt;';
                $content = $this-&gt;settings('checklist_'.$field);
                $c.= '&lt;div&gt;&lt;b&gt;' . ucfirst($field);
                $c.= ' &lt;/b&gt;&lt;input name="p01-contact[settings][checklist_type]['.$field.']"';
                $c.= ' type="radio" value="blacklist" checked /&gt; ' . $this-&gt;lang('blacklist');
                $c.= ' &lt;input name="p01-contact[settings][checklist_type]['.$field.']" ';
                $c.= ' type="radio" value="whitelist" disabled /&gt; ' . $this-&gt;lang('whitelist') . '&lt;/div&gt;';
                $c.= '&lt;textarea name="p01-contact[settings][checklist]['.$field.']" ';
                $c.= 'style="width:100%;height:'.(40+strlen($content)*0.2).'px"&gt;';
                $c.= $content . '&lt;/textarea&gt;';
        }
        $c.= '&lt;/tr&gt;&lt;/td&gt;';

        //debug
        $c.= '&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;label style="display:block;float:none"&gt;' . $this-&gt;lang('debug') . '&lt;/label&gt;&lt;/b&gt;';
        $c.= '&lt;i&gt;' . $this-&gt;lang('debug_sub') . '&lt;/i&gt;&lt;br /&gt;';
        $c.= '&lt;b&gt;' . $this-&gt;lang('debug_warn') . '&lt;/b&gt;&lt;/td&gt;';
        $c.= '&lt;td&gt;&lt;input type="checkbox" name="p01-contact[settings][debug]" ';
        $c.= $this-&gt;settings('debug') ? 'checked="checked" ' : '';
        $c.= '/&gt;&lt;/td&gt;&lt;/tr&gt;';

        $c.= '&lt;tr&gt;&lt;td&gt;&lt;input type="submit" value="' . $this-&gt;lang('save_set') . '" /&gt;&lt;/td&gt;&lt;/tr&gt;';

        $c.= '&lt;/table&gt;&lt;/form&gt;';

        return $c;
    }

    /*
     * Create an unique hash in SESSION
     */
    private function set_token()
    {
        $_SESSION['p01-contact_token'] = uniqid(md5(microtime()), True);
    }
    /*
     * Get the token in SESSION (create it if not exists)
     * @return string
     */
    public function get_token()
    {
        if(!isset($_SESSION['p01-contact_token']))
            $this-&gt;set_token();
        return $_SESSION['p01-contact_token'];
    }
    /*
     * Compare the POSTed token to the SESSION one
     * @return boolean
     */
    private function check_token()
    {
        if($this-&gt;get_token() === $_POST['p01-contact_form']['token'])
            return True;
        else return False;
    }

    /*
     * Return settings default email if set and valid,
     * or $this-&gt;default_email if set and valid,
     * or False.
     */
    public function get_default_email()
    {
        $settings_email = $this-&gt;settings('default_email');
        $pattern = '`^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,3})$`i';

        if(!empty($settings_email)
        && preg_match($pattern, $settings_email))
            return $settings_email;
        if(!empty($this-&gt;default_email)
        && preg_match($pattern, $this-&gt;default_email))
            return $this-&gt;default_email;

        return False;
    }
}

/*
 * Contact form class

 * Contains fields, manage mail sending.
 */
class P01contact_form
{
    public $P01contact;

    private $id;
    private $status;
    private $targets;
    private $fields;

    /*
     * @param P01contact $P01contact
     * @param int $id the form id
     */
    public function __construct($P01contact, $id)
    {
        $this-&gt;P01contact = $P01contact;

        $this-&gt;id = $id;
        $this-&gt;status = '';
        $this-&gt;targets = array();
        $this-&gt;fields = array();
    }

    /*
     * Return the html display of the form
     * @return string the &lt;form&gt;
     */
    public function html()
    {
        $html  = '&lt;form action="#p01-contact' . $this-&gt;id . '" autocomplete="off" ';
        $html .= 'id="p01-contact' . $this-&gt;id . '" class="p01-contact" method="post"&gt;';

        $html .= $this-&gt;html_status();

        if($this-&gt;status != 'sent') {
            foreach($this-&gt;fields as $id =&gt; $field) $html .= $field-&gt;html();

            $html .= '&lt;div class="otpr"&gt;&lt;input name="p01-contact_form[id]" type="hidden" value="' . $this-&gt;id . '" /&gt;';
            $html .= '&lt;input name="p01-contact_form[token]" type="hidden" value="' . $this-&gt;P01contact-&gt;get_token() . '" /&gt;';
            $html .= '&lt;input class="submit" ';
            $html .= 'type="submit" value="' . $this-&gt;lang('send') . '" /&gt;&lt;p&gt;&lt;span style="color:' . $this-&gt;lang('color') . '"&gt;*&lt;/span&gt; ' . $this-&gt;lang('note') . '&lt;/p&gt;&lt;/div&gt;';
        }
        $html .= '&lt;/form&gt;';

        return $html;
    }

    /*
     * Return an html display of the form status
     * @return string the &lt;div&gt;
     */
    private function html_status()
    {
        if(!$this-&gt;status) return '';
        $style = '
	        margin:20px 0 400px 0;
	        background:#FCFBB8;
	        line-height:30px;
	        padding:0 10px;
	        border:1px solid #F9CF51;
	        border-radius: 5px;
	        -moz-border-radius: 5px;
	        -khtml-border-radius: 5px;
	        -webkit-border-radius: 5px;';
        $style .= $this-&gt;status == 'sent' ? 'color:#308000;' : 'color:#D94136;';

        return '&lt;div class="fix" style="'.$style.'"&gt;' . $this-&gt;lang($this-&gt;status) . '&lt;/div&gt;';
    }

    /*
     * Return an html http:// link
     * @param string $href the link address
     * @param string $title if not used, the link title will be the address
     * @return string the &lt;a&gt;
     */
    private function html_link($href, $title = False)
    {
        if(!$title) $title = $href;
        return '&lt;a href="http://' . $href . '"&gt;' . $title . '&lt;/a&gt;';
    }

    /*
     * Return an html mailto: link
     * @param string $href the email
     * @param string $title if not used, the link title will be the email
     * @return string the &lt;a&gt;
     */
    private function html_mail_link($href, $title = False)
    {
        if(!$title) $title = $href;
        return '&lt;a href="mailto:' . $href . '"&gt;' . $title . '&lt;/a&gt;';
    }

    /**
     * Send a mail based on form
     *
     * Create the mail content and headers along to settings, form
     * and fields datas; and update the form status (sent|error).
     */
    public function send_mail()
    {
        $server = $_SERVER['SERVER_NAME'];
        $uri = $_SERVER['REQUEST_URI'];

        // title
        $content  = '&lt;h2&gt;' . $this-&gt;lang('fromsite') . ' &lt;i&gt;' . $_SERVER['SERVER_NAME'] . '&lt;/i&gt;&lt;/h2&gt;';
        $content .= '&lt;h3&gt;' . date('r') . '&lt;/h3&gt;&lt;br/&gt;';

        // fields
        $skip = array('captcha');
        foreach($this-&gt;fields as $field)
        {
            $type  = $field-&gt;get_type();
            $value = $field-&gt;get_value();
            $title = $field-&gt;get_title();
            if($type == 'name')
                $name = $value;
            elseif($type == 'email')
                $email = $value;
            elseif($type == 'subject')
                $subject = $value;
            elseif(
                !in_array($type, $skip)
                && !empty($value))
            {
                $title = !empty($title) ? $title : $type;
                if($type != 'askcopy') // managed blow for him.
                    $content .= '&lt;p&gt;&lt;b&gt;' . $this-&gt;lang($title).' :&lt;/b&gt; ';
                switch($type)
                {
                    case 'message' :
                    case 'textarea' :
                        $content .= '&lt;p style="margin:10px;padding:10px;border:1px solid silver"&gt;';
                        $content .= nl2br($value) . '&lt;/p&gt;';
                        break;
                    case 'website' :
                        $content .= $this-&gt;html_link($value);
                        break;
                    case 'checkbox' :
                    case 'select' :
                    case 'radio' :
                        $content .= '&lt;ul&gt;';
                        foreach($value as $v)
                            if(isset($v[2]) && $v[2] == 'selected')
                                $content .=  '&lt;li&gt;' . $v[1] . '&lt;/li&gt;';
                        $content .= '&lt;/ul&gt;';
                        break;
                    case 'askcopy' :
                        $askcopy = True;
                        $content .= '&lt;p&gt;&lt;b&gt;' . $this-&gt;lang('askedcopy').'.&lt;/b&gt;&lt;/p&gt;';
                        break;
                    default :
                        $content .=  $value;
                }
                $content .= '&lt;/p&gt;';
            }
        }
        if(!isset($askcopy)) $askcopy = False;

        // footer infos
        $footer  = '&lt;p&gt;&lt;i&gt;' . $this-&gt;lang('sentfrom');
        $footer .= ' ' . $this-&gt;html_link($server.$uri, $uri);
        $footer_copy = $footer . '&lt;/i&gt;&lt;/p&gt;'; // version without infos below
        $footer .= '&lt;br /&gt;If this mail should not be for you, please contact ';
        $footer .= $this-&gt;html_mail_link($this-&gt;P01contact-&gt;get_default_email());
        $footer .= '&lt;/i&gt;&lt;/p&gt;';

        $targets = implode(',', $this-&gt;targets);

        if(empty($name)) $name = $this-&gt;lang('nofrom');
        if(empty($email)) {
            $askcopy = False;
            $email = $this-&gt;lang('nofrom');
        }
        if(empty($subject)) $subject = $this-&gt;lang('nosubject');
        $subject = '=?utf-8?B?' . base64_encode($subject) . '?=';

        $headers  = "From: $name &lt;$email&gt;\\r\
";
        $headers .= "Reply-To: $name &lt;$email&gt;\\r\
";
        $headers .= "Return-Path: $name &lt;$email&gt;\\r\
";
        $headers .= "MIME-Version: 1.0\\r\
";
        $headers .= "Content-type: text/html; charset=UTF-8\\r\
";
        $headers .= "X-Mailer: PHP/" . phpversion() . "\\r\
" ;

        if(!$this-&gt;settings('debug')) {
            // send mail
            $status = mail($targets, $subject, $content.$footer, $headers);
            if($status) {
                if($askcopy) { // send copy
                    $copy = mail($email, $subject, $content.$footer_copy, $headers);
                    if($copy) $this-&gt;status = $this-&gt;lang('sent_copy');
                    else $this-&gt;status = $this-&gt;lang('error_copy');
                } else $this-&gt;status = 'sent';
            } else $this-&gt;status = 'error';
        } else {
            // display mail for debug
            echo'&lt;h2 style="color:#c33"&gt;p01-contact (not) sent mail :&lt;/h2&gt;';
            echo'&lt;pre&gt;' . $headers . '&lt;/pre&gt;';
            echo'&lt;div style="border:1px solid black;padding:10px"&gt;' . $content.$footer . '&lt;/div&gt;';
            $this-&gt;status = $this-&gt;lang('debug');
        }
    }

    /*
     * Reset all fields values and errors
     */
    public function reset()
    {
        foreach($this-&gt;fields as $id =&gt; $field) {
            $field-&gt;set_value('');
            $field-&gt;set_error('');
        }
    }

    /**
     * GETTERS / SETTERS
     */

    public function add_target($tget) {$this-&gt;targets[] = $tget;}
    public function set_targets(array $targets) {$this-&gt;targets = $targets;}
    public function count_targets() {return count($this-&gt;targets);}

    public function get_field($id) {return $this-&gt;fields[$id];}
    public function get_fields() {return $this-&gt;fields;}
    public function add_field(P01contact_field $field) {$this-&gt;fields[] = $field;}

    public function set_status($status) {
        if(is_string($status)) $this-&gt;status = $status;
    }

    public function get_id() {return $this-&gt;id;}
    public function get_status() {return $this-&gt;status;}

    public function settings($key) {return $this-&gt;P01contact-&gt;settings($key);}
    public function lang($key) {return $this-&gt;P01contact-&gt;lang($key);}
}

class P01contact_field
{
    private $form;

    private $id;
    private $type;
    private $title;
    private $value;
    private $required;
    private $locked;
    private $error;

    /*
     * @param P01contact_form $form the container form
     * @param int $id the field id
     * @param string $type the field type
     */
    public function __construct($form, $id, $type)
    {
        $this-&gt;form = $form;

        $this-&gt;id = $id;
        $this-&gt;type = $type;
        $this-&gt;title = '';
        $this-&gt;value = '';
        $this-&gt;required = False;
        $this-&gt;locked = False;
        $this-&gt;error = '';
    }

    /**
     * Check field value
     *
     * Check if field is empty and required or
     * not empty but not valid.
     * @return string the error key, or empty
     */
    public function check_content()
    {
        if(empty($this-&gt;value) && $this-&gt;required) {
            // empty and required
            return 'field_required';
        }
        elseif(!empty($this-&gt;value) && !$this-&gt;check_validity()) {
            // not empty but not valid
            return 'field_' . $this-&gt;type;
        }
        else return '';
    }

    /**
     * Check if field value is valid
     * Mean different things depending on field type
     * @return boolean
     */
    public function check_validity()
    {
        if($this-&gt;blacklisted()) return False;

        switch($this-&gt;type) {
            case 'email':
                $pattern = '`^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,3})$`i';
                if(preg_match($pattern, $this-&gt;value)) return True;
                else return False;
            case 'phone':
                $pattern = '`^\\+?[-0-9(). ]{6,}$$`i';
                if(preg_match($pattern, $this-&gt;value)) return True;
                else return False;
            case 'website':
                $pattern = "`^((http|https|ftp):\\/\\/(www\\.)?|www\\.)[a-zA-Z0-9\\_\\-]+\\.([a-zA-Z]{2,4}|[a-zA-Z]{2}\\.[a-zA-Z]{2})(\\/[a-zA-Z0-9\\-\\._\\?\\&=,'\\+%\\$#~]*)*$`i";
                if(preg_match($pattern, $this-&gt;value)) return 1;
                else return False;
            case 'message':
                $size = strlen($this-&gt;value);
                if($size &gt; $this-&gt;form-&gt;settings('message_len')) return True;
                else return False;
            case 'captcha':
                include_once CAPTCHAPATH . 'securimage.php';
                $securimage = new Securimage();
                if($securimage-&gt;check($this-&gt;value) == False)
                    return False;
                else return True;
            case 'fieldcaptcha':
                if(!empty($this-&gt;value)) return False;
                else return True;
            case 'password':
                if($this-&gt;value == $this-&gt;required)
                    return True;
                else return False;
            default:
                return True;
        }
    }

    /**
     * Check if field value is blacklisted
     *
     * Search any entry of config file field type
     * blacklist in field value.
     * @return boolean
     */
    public function blacklisted()
    {
        $list = $this-&gt;form-&gt;settings('checklist_' . $this-&gt;type);
        if(empty($list)) return False;

        $array = explode(',', $list);
        foreach($array as $avoid) {
            if(preg_match('`' . $avoid . '`', $this-&gt;value))
                return True;
        }
        return False;
    }

    /*
     * Return the html display of the field
     *
     * Manage field title, error message, and type-based display
     * @return string the &lt;div&gt;
     */
    public function html()
    {
        $id  = 'p01-contact' . $this-&gt;form-&gt;get_id() . '_field' . $this-&gt;id;
        $name = 'p01-contact_fields[' . $this-&gt;id . ']';
        $type = $this-&gt;general_type();
        $value = $this-&gt;value;
        $disabled = $this-&gt;locked ? ' disabled="disabled"' : '';

        $html  = '
        &lt;div class="field ' . $type . '"&gt;';
        if($this-&gt;type != 'askcopy') // not needed here, the value say everything
            $html .= $this-&gt;html_label($id);

        switch($type) {
            case 'text' :
                $html .= '
                &lt;input id="' . $id . '" ';
                $html .= 'name="' . $name . '" type="text" ';
                $html .= 'value="' . $value . '"' . $disabled . ' /&gt;';
                break;
            case 'textarea' :
                $html .= '
                &lt;textarea id="' . $id . '" rows="10" ';
                $html .= 'name="' . $name . '"' . $disabled;
                $html .= '&gt;' . $value . '&lt;/textarea&gt;';
                break;
            case 'captcha' :
                $html .= '
                    &lt;div class="captchaimg"&gt;';
                $html .= '&lt;img id="captchaimg" ';
                $html .=    'src="' . $this-&gt;securimage_url() . 'securimage_show.php" ';
                $html .=    'alt="CAPTCHA Image" /&gt;';
                $html .= '&lt;/div&gt;&lt;/label&gt;&lt;/div&gt;
                &lt;input id="' . $id . '" ';
                $html .= 'type="text" name="' . $name . '" ';
                $html .= 'size="10" maxlength="6"' . $disabled . ' /&gt;
				                &lt;a class="reload" href="#"';
                $html .= 'onclick="document.getElementById(\\'captchaimg\\').src = ';
                $html .= '\\'' . $this-&gt;securimage_url() . 'securimage_show.php?\\' ';
                $html .= '+ Math.random(); return false"&gt;';
                $html .= $this-&gt;form-&gt;lang('reload');
                $html .= '&lt;/a&gt;';
                break;
            case 'fieldcaptcha' :
                $html .= '&lt;input id="' . $id . '" type="text" name="' . $name . '" /&gt;';
                break;
            case 'checkbox' :
                foreach($this-&gt;value as $i =&gt; $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : '';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? ' checked' : '';
                    $html .= '
                    &lt;input id="' . $id . '_option' . $i . '"';
                    $html .= ' type="checkbox" name="' . $name . '[' . $i . ']"';
                    $html .= ' value="' . $value . '"' . $disabled . $selected;
                    $html .= ' /&gt;' . $value;
                }
                break;
            case 'select' :
                $html .= '
                &lt;select id="' . $id . '" name="' . $name . '"' . $disabled . '&gt;';
                foreach($this-&gt;value as $i =&gt; $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : ' Default';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? 'selected="selected"' : '';
                    $html .= '
                    &lt;option id="' . $id . '_option' . $i . '" value="' . $value;
                    $html .= '"' . $selected . ' &gt;' . $value . '&lt;/option&gt;';
                }
                $html.= '&lt;/select&gt;';
                break;
            case 'radio' :
			$html .= '&lt;div class="radio-selector" id="rselect' . $id . '"&gt;';
                foreach($this-&gt;value as $i =&gt; $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : ' Default';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? ' checked' : '';
					
                    $html .= '
                    &lt;input id="' . $id . '_option' . $i . '" type="radio" ';
                    $html .= 'name="' . $name . '" value="' . $value . '"';
                    $html .= $disabled . $selected . ' /&gt;';
					$html .= '
                    &lt;label for="' . $id . '_option' . $i . '" ';
					$html .= '
                    class="' . $id . '_option' . $i . '" ';
                    $html .= $disabled . $selected . ' /&gt;' . $value . '&lt;/label&gt;';
					
                }
				$html .= '&lt;/div&gt;';
                break;
            case 'password' :
                $html .= '
                &lt;input id="' . $id . '" ';
                $html .= 'name="' . $name . '" type="password" ';
                $html .= $disabled . ' /&gt;';
                break;
            case 'file' :
                $html .= '&lt;input id="' . $id . '" ';
                $html .= 'type="file" name="' . $name . '" /&gt;';
                break;
        }
        $html .= '&lt;/div&gt;';
        return $html;
    }

    /*
     * Return the label of the field
     * @param string $for id of the target field
     * @return string the &lt;div&gt; (unclosed for captcha)
     */
    private function html_label($for)
    {
        $html  = '
                &lt;div class="label"&gt;';
        $html .= '&lt;label for="' . $for . '"&gt;';
        if(!empty($this-&gt;title)) {
            $html .= $this-&gt;title;
        } else $html .= ucfirst($this-&gt;form-&gt;lang($this-&gt;type));

        $html .= $this-&gt;required ? ' &lt;strong style="color:red"&gt;*&lt;/strong&gt;' : '';

        if(!empty($this-&gt;error)) {
            $html .= ' &lt;span style="font-size:0.9em;color:red"&gt;';
            $html .= $this-&gt;form-&gt;lang($this-&gt;error);
            $html .= '&lt;/span&gt;';
        }
        if($this-&gt;type != 'captcha') { // captcha close label after image
            $html .= '&lt;/label&gt;&lt;/div&gt;';
        }
        return $html;
    }

    /**
     * Return the general type of a field, even of specials fields.
     */
    function general_type()
    {
        $types = array(
            'name'    =&gt; 'text',
            'email'   =&gt; 'text',
            'phone'   =&gt; 'text',
            'website' =&gt; 'text',
            'subject' =&gt; 'text',
            'address' =&gt; 'textarea',
            'message' =&gt; 'textarea',
            'file'    =&gt; 'file',
            'captcha' =&gt; 'captcha',
            'askcopy' =&gt; 'checkbox');
        if(isset($types[$this-&gt;type]))
            return $types[$this-&gt;type];
        else return $this-&gt;type;
    }

    /**
     * GETTERS / SETTERS
     */

    public function get_type() {return $this-&gt;type;}

    public function get_title() {return $this-&gt;title;}
    public function set_title($title) {
        if(is_string($title)) $this-&gt;title = $title;
    }

    public function get_value() {return $this-&gt;value;}
    public function set_value($value) {
        if(is_string($value)
        || is_array($value))
        $this-&gt;value = $value;
    }

    public function set_required($required) {
        $this-&gt;required = $required;
    }
    public function set_locked($locked) {
        if(is_bool($locked)) $this-&gt;locked = $locked;
    }
    public function set_error($error) {
        if(is_string($error)) $this-&gt;error = $error;
    }
    public function securimage_url() {
        return $this-&gt;form-&gt;P01contact-&gt;securimage_url;
    }
}

function preint($arr) {echo'&lt;pre&gt;';var_dump($arr);echo'&lt;/pre&gt;';}
function unset_r($a,$i) {
    foreach($a as $k=&gt;$v)
        if(isset($v[$i]))
            unset($a[$k][$i]);
    return $a;
}
?&gt;

Hi,

Rather than changing the PHP all around so that the CS will work would you be adverse to using js/jquery to simply target the parent element?

If you don’t want to use JS I’ll move this to the PHP forum where I meant to move it before :slight_smile:

Yes, we must do in php, please

I’m confused, instead of
input label, input label, input label, input label

you want
input input input input label label label label

Doesn’t seem like a good design decision, please explain.

It’s so that you can style any of the labels depending on which radio is selected using CSS only and no JS. If you have them arranged as per normal (input label, input label) then you can’t go back up the dom and select the parent but by putting all the labels after the inputs you can style any label when an input is checked e.g. if the last label is clicked you can fade out all the labels above it.

As you say its generally not a good design decision but in the case of radios and checkboxes which are fixed width and height you can make room for them by padding the label out and absolutely placing the radio into position (or for a more foolproof version hide the radio altogether and use a background image of a radio in the label and change the image depending on whether checked, not checked or disabled).

Interesting. Try this

            case 'radio' :
			$html .= '<div class="radio-selector" id="rselect' . $id . '">';
                foreach($this->value as $i => $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : ' Default';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? ' checked' : '';
/* original code
                    $html .= ' 
                    <input id="' . $id . '_option' . $i . '" type="radio" ';
                    $html .= 'name="' . $name . '" value="' . $value . '"';
                    $html .= $disabled . $selected . ' />';
					$html .= ' 
                    <label for="' . $id . '_option' . $i . '" ';
					$html .= ' 
                    class="' . $id . '_option' . $i . '" ';
                    $html .= $disabled . $selected . ' />' . $value . '</label>';
 */
 // new code - all inputs followed by all labels
                    $input_html = ' 
                    <input id="' . $id . '_option' . $i . '" type="radio" ';
                    $input_html .= 'name="' . $name . '" value="' . $value . '"';
                    $input_html .= $disabled . $selected . ' />';
					$label_html = ' 
                    <label for="' . $id . '_option' . $i . '" ';
					$label_html .= ' 
                    class="' . $id . '_option' . $i . '" ';
                    $label_html .= $disabled . $selected . ' />' . $value . '</label>';
                 }
//				$html .= '</div>';
				$html .= $input_html . $label_html . '</div>';
                break;

This code output only one input and one lable

Sorry, I knew I was missing something other than caffiene but couldn’t put my finger on it. The variables have to be initialized outside the loop.

            case 'radio' :
			$html .= '<div class="radio-selector" id="rselect' . $id . '">';
// initialize variables
				$input_html = '';
				$label_html = '';
                foreach($this->value as $i => $v) {
                    $value = !empty($v[1]) ? ' ' . $v[1] : ' Default';
                    $selected = !empty($v[2]) && $v[2] == 'selected' ? ' checked' : '';
/* original code
                    $html .= ' 
                    <input id="' . $id . '_option' . $i . '" type="radio" ';
                    $html .= 'name="' . $name . '" value="' . $value . '"';
                    $html .= $disabled . $selected . ' />';
					$html .= ' 
                    <label for="' . $id . '_option' . $i . '" ';
					$html .= ' 
                    class="' . $id . '_option' . $i . '" ';
                    $html .= $disabled . $selected . ' />' . $value . '</label>';
 */
 // new code - all inputs followed by all labels
                    $input_html .= ' 
                    <input id="' . $id . '_option' . $i . '" type="radio" ';
                    $input_html .= 'name="' . $name . '" value="' . $value . '"';
                    $input_html .= $disabled . $selected . ' />';
					$label_html .= ' 
                    <label for="' . $id . '_option' . $i . '" ';
					$label_html .= ' 
                    class="' . $id . '_option' . $i . '" ';
                    $label_html .= $disabled . $selected . ' />' . $value . '</label>';
                 }
//				$html .= '</div>';
				$html .= $input_html . $label_html . '</div>';
                break;