Dynamic HTML_QuickForm Example

Recently I created a dynamically changing HTML_QuickForm (aka HTML_QF, the PEAR module). I have posted it on my site for others to see, as it might come in useful for someone some day.

Please note – this is not final working code, this is an example only. Anyone looking for a RADIUS frontend, this won’t do what you need.

<?php

    require_once 'HTML/QuickForm.php';

    class radForm extends  HTML_QuickForm
    {
        // private var to maintain the viewstate.
        var $_viewstate;

        /**
         *
         * Class constructor
         *
         * Sets up the main form elements, calls the action handler, and renders the extra
         * elements based upon the viewstate.
         */
        function radForm()
        {
            $this->HTML_QuickForm('RadUser');

            // recover the viewstate from the hidden form element
            $this->addElement('hidden', '__VIEWSTATE');
            if ($this->getSubmitValue('__VIEWSTATE'))
            {
                $this->_viewstate = unserialize(base64_decode($this->getSubmitValue('__VIEWSTATE')));
            }
            else
            {
                // defaults it to being an array if not already set
                $this->_viewstate = array();
            }

            // this is added for the javascript to change to allow the action handler (serverside)
            // to read it
            $action =& $this->createElement('hidden', 'action');
            $this->addElement($action);

            // adds the default fields
            $this->addElement('header', null, 'RADIUS Admin');
            $this->addElement('text', 'onsite_id', 'OnSite Ref');
            $this->addElement('text', 'cbuk', 'CBUK');
            $this->addElement('text', 'phonenum', 'Phone Number');
            $this->addElement('text', 'username', 'Username');
            $this->addElement('checkbox', 'active', 'Active');

            // add the select box to allow adding profiles
            $this->addElement('header', null, 'Add Profile');
            $options = array_merge(array(0 => ' -- select a profile -- '), $this->_getProfiles());
            // this adds a JS onchange function to call the serverside actionhandler.
            $this->addElement('select', 'addProfile', 'Add Profile', $options, 'onchange="submitWithAction(\'profileAdd\',this)"');

            // call the action handler
            $this->_actionHandler();

            // this function renders the extra form elements that have been added
            $this->processViewstate();
            $this->_updateViewstate();
            $this->addElement('submit', 'post', 'Submit');
        }

        /**
         *
         * Goes though each profile and adds the profile section to the form
         */
        function processViewstate()
        {
            if (isset($this->_viewstate['profiles']))
            {
                foreach ($this->_viewstate['profiles'] as $profileName => $profileFields)
                {
                    $this->addProfileGroup($profileName, $profileName);
                }
            }
        }

        /**
         *
         * Adds the group select and check/reply options to the form.
         */
        function addProfileGroup($prefix, $name)
        {
            static $index;
            isset($index)?$index++:$index=0;

            // profile title and remove link
            $removeLink = '<a href="#" onclick="submitWithAction(\'profileDel|' . $prefix . '\'); return false;" >remove</a>';
            $this->addElement('header', null, 'Profile ' . $name . ' - '  .  $removeLink);

            // group selector
            $options = array_merge( array(0 => ' -- select a group -- '), $this->_getGroups());
            $this->addElement('select', 'groupAdd[' . $prefix . ']', 'Current Group', $options, 'onchange="submitWithAction(\'groupSet|' . $prefix . '\', this)"');

            // checks
            $options = array_merge( array(0 => ' -- select a check -- '), $this->_getChecks());
            $this->addElement('select', 'checkAdd[' . $prefix . ']', 'Checks', $options, 'onchange="submitWithAction(\'checkAdd|' . $prefix . '\', this)"');
            if (isset($this->_viewstate['profiles'][$prefix]['check']['elements']))
            {
                foreach ($this->_viewstate['profiles'][$prefix]['check']['elements'] as $index => $element)
                {
                    $group = array();
                    $group[] = $this->createElement('select', 'op', null, $this->_getOperators());
                    $group[] = $this->createElement('text', 'value', $element);
                    $group[] = $this->createElement('submit', null, 'remove'    , 'onclick="submitWithAction(\'checkDelete|' . $prefix . '|' . $index . '\')"');
                    $this->addGroup($group, $prefix . '_checks' . $index, $element);
                }
            }

            // replies
            $options = array_merge( array(0 => ' -- select a reply -- '), $this->_getReplies());
            $this->addElement('select', 'replyAdd[' . $prefix . ']', 'Replies', $options, 'onchange="submitWithAction(\'replyAdd|' . $prefix . '\', this)"');
            if (isset($this->_viewstate['profiles'][$prefix]['reply']['elements']))
            {
                foreach ($this->_viewstate['profiles'][$prefix]['reply']['elements'] as $index => $element)
                {
                    $group = array();
                    $group[] = $this->createElement('select', 'op', null, $this->_getOperators());
                    $group[] = $this->createElement('text', 'value', $element);
                    $group[] = $this->createElement('submit', null, 'remove', 'onclick="submitWithAction(\'replyDelete|' . $prefix . '|' . $index . '\')"');
                    $this->addGroup($group, $prefix . '_replys' . $index, $element);
                }
            }


        }

        /**
         *
         *  Function to update the viewstate
         */
        function _updateViewstate()
        {
            $viewstate =& $this->getElement('__VIEWSTATE');
            if (!is_array($this->_viewstate))
            {
                $this->_viewstate = array();
            }
            $viewstate->setValue(base64_encode(serialize($this->_viewstate)));
        }

        /**
         *
         * This function handles the action that would have been set client side in the hidden element
         * All it does is update the viewstate, as the rendering of the form is done elsewhere
         */
        function _actionHandler()
        {
            $actionElement =& $this->getElement('action');
            if (!$actionElement->getValue())
            {
                return true;
            }
            $action = $actionElement->getValue();
            $actionElement->setValue('');

            // actions look like 'profileAdd|something|somethingelse'
            $actions = explode('|',$action);
            switch ($actions[0])
            {
                case 'profileAdd':
                    // resets the addProfile box to the top element.
                    $selectBox =& $this->getElement('addProfile');
                    $selectBox->setValue(0);

                    if (!isset($this->_viewstate['profiles']))
                    {
                        $this->_viewstate['profiles'] = array();
                    }
                    if (!isset($this->_viewstate['profiles'][$actions[1]]))
                    {
                        $this->_viewstate['profiles'][$actions[1]] = array('checks' => array(), 'replys' => array());
                    }
                    break;
                case 'profileDel':
                    // resets the addProfile box to the top element.
                    $selectBox =& $this->getElement('addProfile');
                    $selectBox->setValue(0);
                    unset($this->_viewstate['profiles'][$actions[1]]);
                    break;
                case 'checkAdd':
                    if (!isset($this->_viewstate['profiles'][$actions[1]]['check']['elements']))
                    {
                        $this->_viewstate['profiles'][$actions[1]]['check']['elements'] = array();
                    }
                    array_push($this->_viewstate['profiles'][$actions[1]]['check']['elements'], $actions[2]);
                    break;
                case 'checkDelete':
                    unset($this->_viewstate['profiles'][$actions[1]]['check']['elements'][$actions[2]]);
                    break;
                case 'replyAdd':
                    if (!isset($this->_viewstate['profiles'][$actions[1]]['reply']['elements']))
                    {
                        $this->_viewstate['profiles'][$actions[1]]['reply']['elements'] = array();
                    }
                    array_push($this->_viewstate['profiles'][$actions[1]]['reply']['elements'], $actions[2]);
                    break;
                case 'replyDelete':
                    unset($this->_viewstate['profiles'][$actions[1]]['reply']['elements'][$actions[2]]);
                    break;
            }
            return true;
        }

        /**
         *
         * Returns a list of the profiles
         */
        function _getProfiles()
        {
            // will be read from a database soon
            return array(0 => 'LNS', 1 => 'LTS');
        }

        /**
         *
         * Returns a list of valid operators
         */
        function _getOperators()
        {
            return array('==' => '==',
                           '!=' => '!=',
                           '='  => '=',
                           ':=' => ':=',
                           '<=' => '<=',
                           '>=' => '>=',
                           '>'  => '>',
                           '<'  => '<',
                           '=~' => '=~',
                           '+=' => '+=',
                           '!~' => '!~',
                           '=*' => '=*',
                           '!*' => '!*'
                          );
        }

        /**
         *
         * Returns an array of groups from the database.
         */
        function _getGroups()
        {
            return array (1 => 'group a', 2 => 'group b');
        }

        /**
         *
         * Returns an array of checks
         */
        function _getChecks()
        {
            return array (1 => 'check 1', 2 => 'check 2');
        }

        /**
         *
         * Returns an array of replys
         */
        function _getReplies()
        {
            return array (1 => 'reply 1', 2 => 'reply 2');
        }
    }

?>
<script>
    function submitWithAction(action, selectBox)
    {
        var actionString;

        if (selectBox)
        {
            if (selectBox.selectedIndex == 0)
            {
                return false;
            }
            actionString = action + '|' + selectBox.options[selectBox.selectedIndex].text;
        }
        else
        {
            actionString = action;
        }

        document.RadUser.action.value = actionString;
        document.RadUser.submit();
    }
</script>

<h1>RADIUS User Admin (Expert)</h1>
<?php
    $form = new radForm();

    $form->display();

Irssi – making it beep when your nick is mentioned

Irssi by default will highlight your nickname, but that actually requires you to be looking at the screen. I wanted to make irssi beep when someone mentioned my nick, so that I didn’t have to actively monitor the tab in konsole. Here’s how to do it.

/set bell_beeps ON
/set beep_msg_level MSGS NOTICES DCC DCCMSGS HILIGHT