Passed
Push — main ( 2edd53...9e1454 )
by Stefan
02:35
created

FormButtonBox::fromXML()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 2
nop 2
dl 0
loc 18
rs 9.8333
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Formgenerator;
5
6
/**
7
 * Button-Box with standrad buttons to control the form.
8
 * 
9
 * Supports the most used 'control' buttons for a form like
10
 * [OK] [Save] [Cancel] ...
11
 * Custom defined buttons can also be added.
12
 * Language can be configured through the config file.
13
 *
14
 * @package Formgenerator
15
 * @author Stefanius <[email protected]>
16
 * @copyright MIT License - see the LICENSE file for details
17
 */
18
class FormButtonBox extends FormElement
19
{
20
    public const NONE       = 0;
21
    public const FIRST      = 0;
22
    public const LAST       = -1;
23
    public const OK         = 0x0001; // An "OK" button for submit.
24
    public const OPEN       = 0x0002; // An "Open" button for submit.
25
    public const SAVE       = 0x0004; // A "Save" button for submit.
26
    public const YES        = 0x0008; // A "Yes" button for submit.
27
    public const NO         = 0x0010; // A "No" button
28
    public const CANCEL     = 0x0020; // A "Cancel" button
29
    public const CLOSE      = 0x0040; // A "Close" button
30
    public const DISCARD    = 0x0080; // A "Discard" button
31
    public const APPLY      = 0x0100; // An "Apply" button for submit.
32
    public const RESET      = 0x0200; // A "Reset" button
33
    public const RETRY      = 0x0400; // A "Retry" button for submit.
34
    public const IGNORE     = 0x0800; // An "Ignore" button
35
    public const BACK       = 0x1000; // A "Back" button
36
    
37
    public const YES_NO_CANCEL = self::YES | self::NO | self::CANCEL;
38
    public const SAVE_CANCEL = self::SAVE | self::CANCEL;
39
    
40
    /** @var integer Buttons, the box containing     */
41
    protected int $iBtns = 0;
42
    /** @var array user defined button(s)     */
43
    protected array $aCustomButtons = [];
44
45
    /**
46
     * @param int $iBtns
47
     */
48
    public function __construct(int $iBtns, int $wFlags = 0)
49
    {
50
        $this->iBtns = $iBtns;
51
        parent::__construct($wFlags);
52
    }
53
    
54
    /**
55
     * {@inheritDoc}
56
     * @see \SKien\Formgenerator\FormElement::fromXML()
57
     */
58
    static public function fromXML(\DOMElement $oXMLElement, FormCollection $oFormParent) : ?FormElement
59
    {
60
        $iBtns = 0;
61
        if (($aBtns = self::getAttribStringArray($oXMLElement, 'buttons')) !== null) {
62
            foreach ($aBtns as $strBtn) {
63
                $strConstName = 'self::' . strtoupper($strBtn);
64
                if (defined($strConstName)) {
65
                    $iBtns += constant($strConstName);
66
                } else {
67
                    trigger_error('Unknown Constant [' . $strConstName . '] for the Button property!', E_USER_WARNING );
68
                }
69
            }
70
        }
71
        $wFlags = self::getAttribFlags($oXMLElement);
72
        $oFormElement = new self($iBtns, $wFlags);
73
        $oFormParent->add($oFormElement);
74
        $oFormElement->readAdditionalXML($oXMLElement); // TODO: support of custom buttons through XML
75
        return $oFormElement;
76
    }
77
    
78
    /**
79
     * Add custom button to the buttonbox.
80
     * Position of the button inside the box can be specified with the param $iAfterBtn: <ul>
81
     * <li> self::FIRST </li>
82
     * <li> self::LAST </li>
83
     * <li> other valid Button: the custom Button appears after this button </li></ul>
84
     * @param string $strText
85
     * @param string $strID
86
     * @param int $iAfterBtn
87
     * @param bool $bSubmit
88
     */
89
    public function addButton(string $strText, string $strID, int $iAfterBtn = self::LAST, bool $bSubmit = false) : void
90
    {
91
        $this->aCustomButtons[$iAfterBtn] = ['text' => $strText, 'id' => $strID, 'type' => ($bSubmit ? 'submit' : 'button')]; 
92
    }
93
94
    /**
95
     * (non-PHPdoc)
96
     *
97
     * @see \SKien\Formgenerator\FormElement::getHTML()
98
     */
99
    public function getHTML() : string
100
    {
101
        if ($this->iBtns === 0) {
102
            return '';
103
        }
104
        if ($this->oFlags->isSet(FormFlags::ALIGN_CENTER)) {
105
            $this->addStyle('text-align', 'center');
106
        } else if ($this->oFlags->isSet(FormFlags::ALIGN_RIGHT)) {
107
            $this->addStyle('text-align', 'right');
108
        }
109
        
110
        $aButtonDef = $this->loadButtonDef();
111
        
112
        $strHTML = '<div id=buttonbox' . $this->buildStyle() . '>' . PHP_EOL;
113
        $iBtn = 0x0001;
114
        $strHTML .= $this->getCustomButton(self::FIRST);
115
        while ($iBtn < 0xffff) {
116
            if (($this->iBtns & $iBtn) != 0) {
117
                $strHTML .= $this->getButton($aButtonDef[$iBtn]);
118
            }
119
            $strHTML .= $this->getCustomButton($iBtn);
120
            $iBtn = $iBtn << 1;
121
        }
122
        $strHTML .= $this->getCustomButton(self::LAST);
123
        $strHTML .= '</div>' . PHP_EOL;
124
        
125
        return $strHTML;
126
    }
127
    
128
    /**
129
     * Set the tab index of first button.
130
     * Method is called from the PageGenerator after an element is added to the form.
131
     * @param int $iTabindex
132
     * @return int the count of buttons (-> number tabindexes 'needed')
133
     */
134
    public function setTabindex(int $iTabindex) : int
135
    {
136
        $this->iTabindex = $iTabindex;
137
        return $this->getButtonCount();
138
    }
139
    
140
    /**
141
     * Build the markup for the button.
142
     * @param array $aBtn
143
     * @return string
144
     */
145
    protected function getButton(array $aBtn) : string
146
    {
147
        $strHTML = '  <input id="' . $aBtn['id'] . '"';
148
        $strHTML .= ' type="' . $aBtn['type'] . '"';
149
        $strHTML .= ' tabindex="' . $this->iTabindex++ . '"';
150
        if ($this->oFlags->isSet(FormFlags::READ_ONLY | FormFlags::DISABLED)) {
151
            if ($aBtn['type'] == 'submit') {
152
                $strHTML .= ' disabled';
153
            }
154
        } else if ($aBtn['type'] != 'submit') {
155
            $strHTML .= ' onclick="' . $aBtn['id'] . 'Clicked();"';
156
        }
157
        $strHTML .= ' value="' . $aBtn['text'] . '"';
158
        $strHTML .= '>' . PHP_EOL;
159
        
160
        return $strHTML;
161
    }
162
163
    /**
164
     * Build custom button, if defined for the requested position.
165
     * @param int $iAfterBtn
166
     * @return string
167
     */
168
    protected function getCustomButton(int $iAfterBtn) : string
169
    {
170
        if (!isset($this->aCustomButtons[$iAfterBtn])) {
171
            return '';
172
        }
173
        return $this->getButton($this->aCustomButtons[$iAfterBtn]);
174
    }
175
176
    /**
177
     * Get the number of buttons the box contains.
178
     * @return int
179
     */
180
    protected function getButtonCount() : int
181
    {
182
        $iCount = 0;
183
        $iBtns = $this->iBtns;
184
        while ($iBtns) {
185
            $iCount += ($iBtns & 1);
186
            $iBtns >>= 1;
187
        }
188
        return $iCount + count($this->aCustomButtons);
189
    }
190
    
191
    /**
192
     * Get Textlabels for all buttons.
193
     * Default they are initialized with the english Text.
194
     * Configuration can contain localization.
195
     * @return array
196
     */
197
    protected function loadButtonDef() : array
198
    {
199
        $aButtonDef = [
200
            self::OK => ['text' => 'OK', 'id' => 'btnOK', 'type' => 'submit'],
201
            self::OPEN => ['text' => 'Open', 'id' => 'btnOpen', 'type' => 'button'],
202
            self::SAVE => ['text' => 'Save', 'id' => 'btnSave', 'type' => 'submit'],
203
            self::YES => ['text' => 'Yes', 'id' => 'btnYes', 'type' => 'submit'],
204
            self::NO => ['text' => 'No', 'id' => 'btnNo', 'type' => 'button'],
205
            self::CANCEL => ['text' => 'Cancel', 'id' => 'btnCancel', 'type' => 'button'],
206
            self::CLOSE => ['text' => 'Close', 'id' => 'btnClose', 'type' => 'button'],
207
            self::DISCARD => ['text' => 'Discard', 'id' => 'btnDiscard', 'type' => 'button'],
208
            self::APPLY => ['text' => 'Apply', 'id' => 'btnApply', 'type' => 'submit'],
209
            self::RESET => ['text' => 'Reset', 'id' => 'btnReset', 'type' => 'button'],
210
            self::RETRY => ['text' => 'Retry', 'id' => 'btnRetry', 'type' => 'submit'],
211
            self::IGNORE => ['text' => 'Ignore', 'id' => 'btnIgnore', 'type' => 'button'],
212
            self::BACK => ['text' => 'Back', 'id' => 'btnBack', 'type' => 'button'],
213
        ];
214
        
215
        $aConfig = $this->oFG->getConfig()->getArray('ButtonBox.ButtonText');
216
        // To make it easier to read, the configuration contains the names of the constants 
217
        // as keys. So we have to convert the names into the values and assign the texts 
218
        // accordingly.
219
        foreach ($aConfig as $strName => $strText) {
220
            $iBtn = constant('self::' . $strName);
221
            $aButtonDef[$iBtn]['text'] = $strText;
222
        }
223
        return $aButtonDef;
224
    }
225
}
226
227