Passed
Push — main ( e33397...22db30 )
by Stefan
02:01 queued 28s
created

FormElement::parseStyle()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 10
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 14
rs 9.9332
1
<?php
2
namespace SKien\Formgenerator;
3
4
/**
5
 * Base-class for all elements of a form.
6
 * Starting with a FormGenerator-element, the form can contain any count 
7
 * of elements.
8
 * The elements usuallay be arranged within FormFieldSet- and FormLine-elements
9
 *
10
 * #### History
11
 * - *2020-05-12*   initial version
12
 * - *2021-01-07*   PHP 7.4
13
 *
14
 * @package Formgenerator
15
 * @version 1.1.0
16
 * @author Stefanius <[email protected]>
17
 * @copyright MIT License - see the LICENSE file for details
18
 */
19
class FormElement
20
{
21
    /** text-align:left (default)   */
22
    const   ALIGN_LEFT              = 0x000000;
23
    /** mandatory field. added to mandatory-list for JS validation    */
24
    const   MANDATORY               = 0x000001;
25
    /** hidden field    */
26
    const   HIDDEN                  = 0x000002;
27
    /** readonly field  */
28
    const   READ_ONLY               = 0x000004;
29
    /** text-align:right    */
30
    const   ALIGN_RIGHT             = 0x000008;
31
    /** field is extended with DTU (Date-Time-User) Button  */
32
    const   ADD_DTU                 = 0x000010;
33
    /** field is extendet with selectbutton (click calls javascript function OnSelect(strField) with fieldname    */
34
    const   ADD_SELBTN              = 0x000020;
35
    /** static field is displayed as hint (smaller font, darkgrey)  */
36
    const   HINT                    = 0x000040;
37
    /** static field is displayed as error (red text)   */
38
    const   ERROR                   = 0x000080;
39
    /** button with selectlist  */
40
    const   SELECT_BTN              = 0x000100;
41
    /** field is disabled   */
42
    const   DISABLED                = 0x000400;
43
    /** display static field as info (see stylesheet: .info)    */
44
    const   INFO                    = 0x000800;
45
    /** text-align:center   */
46
    const   ALIGN_CENTER            = 0x001000;
47
    /** field is extended with Cal-Button for datepicker    */
48
    const   ADD_DATE_PICKER         = 0x002000;
49
    /** field is extended with Clock-Button for timepicker  */
50
    const   ADD_TIME_PICKER         = 0x004000;
51
    /** suppress zero-values    */
52
    const   NO_ZERO                 = 0x008000;
53
    /** suppress zero-values    */
54
    const   PASSWORD                = 0x010000;
55
    /** file input  */
56
    const   FILE                    = 0x020000;
57
    /** add EUR - Suffix    */
58
    const   ADD_EUR                 = 0x040000;
59
    /** trim content (leading / trailing blanks)    */
60
    const   TRIM                    = 0x080000;
61
    /** field invokes color picker on click */
62
    const   ADD_COLOR_PICKER        = 0x0100000;
63
    /** set data for CKEdit through JS  */
64
    const   SET_JSON_DATA           = 0x0200000;
65
    /** font-weight: bold   */
66
    const   BOLD                    = 0x0400000;
67
    /** replace '<br/>' / '<br> with CR */
68
    const   REPLACE_BR_CR           = 0x0800000;
69
70
    // TODO: Find a more general way of defining standard images. (possibly via a config)
71
    /** standard delete image */
72
    const IMG_DELETE            = 1;
73
    /** standard delete image */
74
    const IMG_SEARCH            = 2;
75
    /** standard image for date picker */
76
    const IMG_DATE_PICKER       = 3;
77
    /** standard image for time picker */
78
    const IMG_TIME_PICKER       = 4;
79
    /** standard image for dtu insert (DTU: Date,Time,User) */
80
    const IMG_DTU               = 5;
81
    
82
    /** @var FormGenerator the FormGenerator this element belongs to     */
83
    protected ?FormGenerator $oFG = null;
84
    /** @var FormElement the parent element - only FormGenerator has no parent     */
85
    protected ?FormElement $oParent = null;
86
    /** @var array all direct child elements     */
87
    protected array $aChild = array();
88
    /** @var array the width information for the cols inside this element     */
89
    protected ?array $aColWidth = null;
90
    /** @var string dimension of the width values ('%', 'px', 'em')     */
91
    protected string $strWidthDim = '%';
92
    /** @var int tab position of the element if it can get focus     */
93
    protected int $iTab = -1;
94
    /** @var int col inside current line     */
95
    protected int $iCol = 0;
96
    /** @var string element name     */
97
    protected string $strName = '';
98
    /** @var string element id     */
99
    protected string $strID = '';
100
    /** @var string CSS class of the element     */
101
    protected string $strClass = '';
102
    /** @var string validation for the element     */
103
    protected string $strValidate = '';
104
    /** @var int flags that specify the appearance and behaviour     */
105
    protected int $wFlags = 0;
106
    /** @var array attributes of the element     */
107
    protected ?array $aAttrib = null;
108
    /** @var array (CSS) styles of the element     */
109
    protected ?array $aStyle = null;
110
    /** @var bool set to true, if element creates some JS     */
111
    protected bool $bCreateScript = false;
112
    /** @var bool set to true, if element creates some CSS style     */
113
    protected bool $bCreateStyle = false;
114
115
    /**
116
     * nothing to initialize so far.
117
     * Keep it in code because derived classes call the parent constructor. 
118
     */
119
    public function __construct()
120
    {
121
    }
122
    
123
    /**
124
     * Return the FormGenerator this element belongs to.
125
     * @return FormGenerator
126
     */
127
    public function getFG() : ?FormGenerator
128
    {
129
        return $this->oFG;
130
    }
131
132
    /**
133
     * Add a child to this element.
134
     * @param FormElement $oElement
135
     * @return FormElement
136
     */
137
    public function add(FormElement $oElement) : FormElement
138
    {
139
        $oElement->setParent($this);
140
        $this->aChild[] = $oElement;
141
        if ($this->oFG !== null) {
142
            $this->oFG->addElement($oElement);
143
        } else {
144
            trigger_error('No FormGenerator object set!', E_USER_ERROR);
145
        }
146
        
147
        return $oElement;
148
    }
149
150
    /**
151
     * Set the parent of this element.
152
     * The Formgenerator of the parent is adopted for this element. 
153
     * If there are global flags set for the FormGenerator, this flags are added.
154
     * @param FormElement $oParent
155
     */
156
    public function setParent(FormElement $oParent) : void 
157
    {
158
        $this->oParent = $oParent;
159
        $this->oFG = $oParent->oFG;
160
        if ($this->oFG !== null) {
161
            $this->addFlags($this->oFG->getGlobalFlags());
162
        } else {
163
            trigger_error('No FormGenerator object set!', E_USER_ERROR);
164
        }
165
    }
166
    
167
    /**
168
     * Set the current col.
169
     * If this element is added as a child of a FormLine, the column is set in 
170
     * order to be able to calculate the correct width of the element.
171
     * @param int $iCol
172
     */
173
    public function setCol(int $iCol) : void
174
    {
175
        $this->iCol = $iCol;
176
    }
177
178
    /**
179
     * Set width for the cols included in this element.
180
     * @param array $aColWidth
181
     * @param string $strDim
182
     */
183
    public function setColWidth(array $aColWidth, string $strDim = '%') : void 
184
    {
185
        $this->aColWidth = $aColWidth;
186
        $this->strWidthDim = $strDim;
187
    }
188
    
189
    /**
190
     * Get colwidth for requested element.
191
     * If no width set, we try to get the width throught the parent.
192
     * @param int $iCol  requested col, if -1 current col is used
193
     * @return string       colwidth including dimension
194
     */
195
    public function getColWidth(int $iCol = -1) : string 
196
    {
197
        $strWidth = '';
198
        if ($iCol < 0) {
199
            $iCol = $this->iCol;
200
        }
201
        if ($this->aColWidth != null && $iCol < count($this->aColWidth) && $this->aColWidth[$iCol] >= 0) {
202
            $strWidth = $this->aColWidth[$iCol] . $this->strWidthDim;
203
        } else if ($this->oParent != null) {
204
            $strWidth = $this->oParent->getColWidth($iCol);
205
        }
206
        return $strWidth;
207
    }
208
209
    /**
210
     * Add a new div as child.
211
     * @param int $iWidth   width of the div in percent
212
     * @param int $iAlign   align (FormDiv::NONE, FormDiv::LEFT, FormDiv::RIGHT, FormDiv::CLEAR)
213
     * @param string $strID ID of the div
214
     * @return \SKien\Formgenerator\FormDiv created div element
215
     */
216
    public function addDiv(int $iWidth = 0, int $iAlign = FormDiv::CLEAR, string $strID = '') : FormDiv
217
    {
218
        $oDiv = new FormDiv($iWidth, $iAlign);
219
        $oDiv->SetID($strID);
220
        $this->add($oDiv);
221
    
222
        return $oDiv;
223
    }
224
    
225
    /**
226
     * Add a new fieldset to the element.
227
     * @param string $strLegend text or image of the legend
228
     * @param string $strID
229
     * @param int $iType type of the legend (FormFieldSet::TEXT or FormFieldSet::IMAGE)
230
     * @return \SKien\Formgenerator\FormFieldSet
231
     */
232
    public function addFieldSet(string $strLegend, string $strID = '', $iType = FormFieldSet::TEXT) : FormFieldSet
233
    {
234
        $oFS = new FormFieldSet($strLegend, $strID, $iType);
235
        $this->add($oFS);
236
    
237
        return $oFS;
238
    }
239
    
240
    /**
241
     * Set ID for the element.
242
     * @param string $strID
243
     */
244
    public function setID(string $strID) : void 
245
    {
246
        $this->strID = $strID;
247
    }
248
    
249
    /**
250
     * Set text for the elements title attribute.
251
     * @param string $strTitle
252
     */
253
    public function setTitle(string $strTitle) : void 
254
    {
255
        if (strlen($strTitle) > 0) {
256
            $this->addAttribute('title', $strTitle);
257
        }
258
    }
259
    
260
    /**
261
     * Set the tab number of the element.
262
     * Element can save given tab number or return false if it has no tabstopp.
263
     * Method is called from the PageGenerator after an element is added to the form.
264
     * @param int $iTab
265
     */
266
    public function setTab(int $iTab) : void
267
    {
268
        $this->iTab = $iTab;
269
    }
270
271
    /**
272
     * Check, if the element has tab stop.
273
     * Derived classes have to decide by its own, if a tab stop is needed. Only if
274
     * this method returns true, the PageGenerator call the setTab() method with
275
     * the next available tab position.
276
     * @return bool
277
     */
278
    public function hasTab() : bool
279
    {
280
        return false;
281
    }
282
    
283
    /**
284
     * Add flags to element. 
285
     * @param int $wFlags
286
     */
287
    public function addFlags(int $wFlags) : void 
288
    {
289
        $this->wFlags |= $wFlags;
290
    }
291
    
292
    /**
293
     * Add any attribute.
294
     * If the attribute allready exist, the value will be overwritten.
295
     * @param string $strName
296
     * @param string $strValue
297
     */
298
    public function addAttribute(string $strName, string $strValue = '') : void 
299
    {
300
        $strName = strtolower($strName);
301
        if ($this->aAttrib == null) {
302
            $this->aAttrib = array();
303
        }
304
        if ($strName == 'style') {
305
            // style should no longer be set through AddAttribute()
306
            trigger_error('use AddStyle() to define additional styles for element!', E_USER_ERROR);
307
        }
308
        $this->aAttrib[$strName] = $strValue;
309
    }
310
311
    /**
312
     * Add any style.
313
     * If the attribute allready exist, the value will be overwritten.
314
     * @param string $strName
315
     * @param string $strValue
316
     */
317
    public function addStyle(string $strName, string $strValue) : void 
318
    {
319
        $strName = strtolower($strName);
320
        if ($this->aStyle == null) {
321
            $this->aStyle = array();
322
        }
323
        $this->aStyle[$strName] = $strValue;
324
    }
325
326
    /**
327
     * Set the CSS class of the element.
328
     * Any previously setting will be overwritten.
329
     * @param string $strClass
330
     */
331
    public function setClass(string $strClass) : void 
332
    {
333
        $this->strClass = $strClass;
334
    }
335
    
336
    /**
337
     * Add additional class to element.
338
     * Class is added to the existing classname separated with a blank <br/>
339
     * Generates a notice, if no class set so far!
340
     * @param string $strClass
341
     */
342
    public function addClass(string $strClass) : void 
343
    {
344
        if (strlen($this->strClass) == 0) {
345
            trigger_error('no class set so far!', E_USER_NOTICE);
346
        }
347
        $this->strClass .= ' ' . $strClass;
348
    }
349
    
350
    /**
351
     * Build the HTML-notation for the element and/or all child elements.
352
     * @return string
353
     */
354
    public function getHTML() : string
355
    {
356
        $strHTML = '';
357
        $iCnt = count($this->aChild);
358
        for ($i = 0; $i < $iCnt; $i++) {
359
            $strHTML .= $this->aChild[$i]->GetHTML();
360
        }
361
        return $strHTML;
362
    }
363
    
364
    /**
365
     * Get JS script related to this element.
366
     * This method gives each element the chance to add special JS script to the 
367
     * current page. <br/>
368
     * <b>This method is only called for elements having member bCreateScript set to true!</b>
369
     * @return string
370
     */
371
    public function getScript() : string
372
    {
373
        return '';
374
    }
375
    
376
    /**
377
     * Get styles related to this element.
378
     * This method gives each element the chance to add special styles to the 
379
     * current page. <br/>
380
     * <b>This method is only called for elements having member bCreateStyle set to true!</b>
381
     * @return string
382
     */
383
    public function getStyle() : string
384
    {
385
        return '';
386
    }
387
    
388
    /**
389
     * Build the 'container' div arround the current element.
390
     * Additional styles (alignment, ...) can be passed.
391
     * @param string $strStyle
392
     * @return string
393
     */
394
    protected function buildContainerDiv(string $strStyle = '') : string
395
    {
396
        if (strpos($strStyle, 'float') === false) {
397
            $strStyle = 'float: left; ' . $strStyle;
398
        }
399
        $strWidth = $this->getColWidth();
400
        if (!empty($strWidth)) {
401
            $strStyle = rtrim($strStyle, ';');
402
            $strStyle .= '; width: ' . $strWidth . ';';
403
        }
404
        $strHTML = '<div style="' . $strStyle . '">';
405
406
        return $strHTML;
407
    }
408
    
409
    /**
410
     * Build the style attribute for the element.
411
     * @return string
412
     */
413
    protected function buildStyle() : string
414
    {
415
        $strStyle = '';
416
        if ($this->aStyle != null) {
417
            $strStyle = ' style="';
418
            foreach ($this->aStyle as $strName => $strValue) {
419
                $strStyle .= ' ' . $strName . ': ' . $strValue . ';';
420
            }
421
            $strStyle .= '"';
422
        }
423
        return $strStyle;
424
    }
425
426
    /**
427
     * Build all defined attributes for the element.
428
     * @return string
429
     */
430
    protected function buildAttributes() : string
431
    {
432
        $strAttrib = '';
433
        if ($this->aAttrib != null) {
434
            foreach ($this->aAttrib as $strName => $strValue) {
435
                $strAttrib .= ' ' . $strName;
436
                if (strlen($strValue) > 0) {
437
                    $strAttrib .= '="' . $strValue . '"';
438
                }
439
            }
440
        }
441
        return $strAttrib;
442
    }
443
    
444
    /**
445
     * Build the markup for the value attribute.
446
     * @param mixed $value
447
     * @return string Empty string if no value set, complete attribute if set
448
     */
449
    protected function buildValue($value) : string
450
    {
451
        $strValue = '';
452
        if (!empty($value)) {
453
            $strValue = ' value="' . $value . '"';
454
        }
455
        return $strValue;
456
    }
457
458
    /**
459
     * Build the markup for the class attribute.
460
     * @return string Empty string if no class set, complete attribute if set
461
     */
462
    protected function buildClass() : string
463
    {
464
        $strClass = '';
465
        if (!empty($this->strClass)) {
466
            $strClass .= ' class="' . $this->strClass . '"';
467
        }
468
        return $strClass;
469
    }
470
471
    /**
472
     * Build the markup for the ID attribute.
473
     * @return string Empty string if no id set, complete attribute if set
474
     */
475
    protected function buildID() : string
476
    {
477
        $strID = '';
478
        if (!empty($this->strID)) {
479
            $strID .= ' id=' . $this->strID;
480
        }
481
        return $strID;
482
    }
483
    
484
    /**
485
     * Build the markup for the tabindex attribute.
486
     * @param int $iTab
487
     * @return string Empty string if $iTab = 0, complete attribute if set
488
     */
489
    protected function buildTab(int $iTab) : string
490
    {
491
        $strTab = '';
492
        if ($iTab > 0) {
493
            $strTab = ' tabindex="' . $iTab . '"';
494
        }
495
        return $strTab;
496
    }
497
    
498
    /**
499
     * Get filename for predifined standard images
500
     * @param int $iImage
501
     * @return string
502
     */
503
    protected function getStdImage(int $iImage) : string
504
    {
505
        // TODO: Find a more general way of defining standard images. (possibly via a config)
506
        $strPath = '../images/';
507
        if ($this->oFG !== null) {
508
            $strPath = $this->oFG->getImagePath();
509
        }
510
        $aImage = array(
511
            self::IMG_DELETE                => '16x16/admin_delete.png',
512
            self::IMG_SEARCH                => '16x16/search.png',
513
            self::IMG_DATE_PICKER           => '16x16/datepicker.png',
514
            self::IMG_TIME_PICKER           => '16x16/timepicker.png',
515
            self::IMG_DTU                   => '16x16/admin_dtu.png',
516
        );
517
        
518
        $strImg = '';
519
        if (isset($aImage[$iImage])) {
520
            $strImg = $strPath . $aImage[$iImage];
521
        }
522
        return $strImg;
523
    }
524
    
525
    /**
526
     * Parse a given style attribute into the components it contains.
527
     * @param string $strStyle
528
     * @return array
529
     */
530
    static public function parseStyle($strStyle) : array
531
    {
532
        $aStyle = array();
533
        $aStyles = explode(';', trim($strStyle));
534
        foreach ($aStyles as $strStyleDef) {
535
            $aStyleDef = explode(':', trim($strStyleDef));
536
            if (count($aStyleDef) == 2) {
537
                $strName = trim($aStyleDef[0]);
538
                $strValue = trim($aStyleDef[1]);
539
                $strValue = rtrim($strValue, ';');
540
                $aStyle[$strName] = $strValue;
541
            }
542
        }
543
        return $aStyle;
544
    }
545
    
546
}
547
548