FormButtonBox::getButtonCount()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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