BuildFormBootstrap.php 22.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 1/25/16
 * Time: 10:00 PM
 */

namespace qfq;

use qfq;
12
use qfq\UserFormException;
13
14

require_once(__DIR__ . '/../qfq/Constants.php');
15
require_once(__DIR__ . '/../qfq/helper/OnArray.php');
16
require_once(__DIR__ . '/../qfq/AbstractBuildForm.php');
17
require_once(__DIR__ . '/../qfq/exceptions/UserFormException.php');
18

Carsten  Rose's avatar
Carsten Rose committed
19
20
21
22
/**
 * Class BuildFormBootstrap
 * @package qfq
 */
23
24
class BuildFormBootstrap extends AbstractBuildForm {

25
26
27
28
29
30
31
32
33
34
    private $isFirstPill;

    /**
     * @param array $formSpec
     * @param array $feSpecAction
     * @param array $feSpecNative
     */
    public function __construct(array $formSpec, array $feSpecAction, array $feSpecNative) {
        parent::__construct($formSpec, $feSpecAction, $feSpecNative);
        $this->isFirstPill = true;
35
36

        // Set some defaults
37
38
39
//        if (!isset($this->formSpec['class'])) {
//            $this->formSpec['class'] = 'container';
//        }
Carsten  Rose's avatar
Carsten Rose committed
40

41
//        $this->formSpec['class'] = 'none';
42
43
    }

Carsten  Rose's avatar
Carsten Rose committed
44
45
46
    /**
     *
     */
47
    public function fillWrap() {
48
49
50
51

//        $this->wrap[WRAP_SETUP_OUTER][WRAP_SETUP_START] = '<div class="tab-content">';
//        $this->wrap[WRAP_SETUP_OUTER][WRAP_SETUP_END] = '</div>';

52
53
        $this->wrap[WRAP_SETUP_TITLE][WRAP_SETUP_START] = "<div class='row hidden-xs'><div class='col-md-12'><h1>";
        $this->wrap[WRAP_SETUP_TITLE][WRAP_SETUP_END] = "</h1></div></div>";
54

55
        // Element: Label + Input + Note
56
        $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_START] = "<div class='form-group clearfix'>";
57
        $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_END] = "</div>";
58

59
60
        $this->wrap[WRAP_SETUP_SUBRECORD][WRAP_SETUP_START] = "<div class='col-md-12'>";
        $this->wrap[WRAP_SETUP_SUBRECORD][WRAP_SETUP_END] = "</div>";
61

62
63
        $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_START] = "";
        $this->wrap[WRAP_SETUP_IN_FIELDSET][WRAP_SETUP_END] = "";
64

65
66
67
        $this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_START] = "";
        $this->wrap[WRAP_SETUP_IN_TEMPLATE_GROUP][WRAP_SETUP_END] = "";

68
69
//        $this->feDivClass['radio'] = 'radio';
//        $this->feDivClass['checkbox'] = 'checkbox';
70
71
    }

72
73
74
75
76
77
    /**
     * @param $label
     * @param $input
     * @param $note
     */
    public function fillWrapLabelInputNote($label, $input, $note) {
78
        $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_START] = "<div class='col-md-$label qfq-label'>";
79
80
81
        $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_END] = "</div>";
        $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_START] = "<div class='col-md-$input'>";
        $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_END] = "</div>";
Carsten  Rose's avatar
Carsten Rose committed
82
        $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_START] = "<div class='col-md-$note qfq-note'>";
83
84
85
86
        $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_END] = "</div>";

    }

Carsten  Rose's avatar
Carsten Rose committed
87
88
89
    /**
     * @return string
     */
90
91
92
93
    public function getProcessFilter() {
        return FORM_ELEMENTS_NATIVE_SUBRECORD;
    }

Carsten  Rose's avatar
Carsten Rose committed
94
95
96
    /**
     * @return string
     */
97
98
99
100
101
102
103
104
    public function doSubrecords() {
        return '';
    }

    /**
     * @return string
     */
    public function head() {
105
        $html = '';
106

107
        $html .= '<div ' . Support::doAttribute('class', $this->formSpec[F_CLASS], TRUE) . '>'; // main <div class=...> around everything, Whole FORM; class="container" or class="container-fluid"
108

109
        //TODO: nicer error reporting - make test with 'unknown index' here - unset($this->formSpec['title']) - See #3424
110
111
112
        $title = Support::wrapTag('<div class="hidden-xs col-sm-6 col-md-8">', Support::wrapTag('<h3>', $this->formSpec['title']));
        $button = Support::wrapTag('<div class="col-xs-12 col-sm-6 col-md-4">', $this->buildButtons());
        $html .= Support::wrapTag('<div class="row">', $title . $button);
113
114


115
116
        $pill = $this->buildPillNavigation(OnArray::filter($this->feSpecNative, 'type', 'pill'));
        $html .= Support::wrapTag('<div class="row">', $pill);
117

118
119
        $html .= $this->getFormTag();

120
121
122
123
124
        $class = ['tab-content', $this->formSpec[F_CLASS_BODY]];
        if ($pill == '') {
            $class[] = 'col-md-12';
        }
        $html .= "<div " . Support::doAttribute('class', $class) . ">";
125
126
127
128

        return $html;
    }

129
130
131
132
133
134
    /**
     * Creates a Checkbox, which toggles 'hide'/'unhide' via JS, on all elements with class= CLASS_FORM_ELEMENT_EDIT.
     *
     * @return string - the rendered Checkbox
     */
    private function buildShowEditFormElementCheckbox() {
Carsten  Rose's avatar
Carsten Rose committed
135
        // EditFormElement Icons
136
137
        $js = '$(".' . CLASS_FORM_ELEMENT_EDIT . '").toggleClass("hidden")';
        $element = "<input type='checkbox' onchange='" . $js . "'>" .
138
            Support::wrapTag("<span title='Toggle: Edit form element icons' class='" . GLYPH_ICON . ' ' . GLYPH_ICON_TASKS . "'>", '');
139
        $element = Support::wrapTag('<label class="btn btn-default navbar-btn">', $element);
Carsten  Rose's avatar
Carsten Rose committed
140

141
142
143
        return Support::wrapTag('<div class="btn-group" data-toggle="buttons">', $element);
    }

Carsten  Rose's avatar
Carsten Rose committed
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    /**
     * Creates a link to open current form loaded in FormEditor
     *
     * @return string - the rendered Checkbox
     */
    private function buildViewForm() {

        switch ($this->formSpec[F_NAME]) {
            case 'form':
                $form = $this->store->getVar(F_NAME, STORE_RECORD);
                break;
            case 'formElement':
                $row = $this->db->sql("SELECT f.name FROM Form AS f WHERE id=" . $this->store->getVar(FE_FORM_ID, STORE_RECORD), ROW_EXPECT_1);
                $form = current($row);
                break;
            default:
                return '';
        }

        if ($form === false) {
            return '';
        }

        $queryStringArray = [
            'id' => $this->store->getVar(SYSTEM_EDIT_FORM_PAGE, STORE_SYSTEM),
            'form' => $form,
            'r' => 0
        ];
        $queryString = Support::arrayToQueryString($queryStringArray);
        $sip = $this->store->getSipInstance();
        $url = $sip->queryStringToSip($queryString);

        $toolTip = "View current form with r=0" . PHP_EOL . PHP_EOL . OnArray::toString($queryStringArray, ' = ', PHP_EOL, "'");

        return $this->buildButtonAnchor('form-view-' . $this->formSpec[F_ID], $url, $toolTip, GLYPH_ICON_VIEW, '');

    }

    //        glyphicon glyphicon-eye-open

184
    /**
185
     * Build Buttons panel on top right corner of form.
186
     * Simulate Submit Button: http://www.javascript-coder.com/javascript-form/javascript-form-submit.phtml
187
188
189
190
191
     *
     * @return string
     */
    private function buildButtons() {
        $buttonNew = '';
192
193
194
195
        $buttonDelete = '';
        $buttonClose = '';
        $buttonSave = '';
        $buttonEditForm = '';
Carsten  Rose's avatar
Carsten Rose committed
196
197
198
199
200
        $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);


        // Button: FormEdit
        if ($this->showDebugInfo) {
201
            $toolTip = "Edit form" . PHP_EOL . PHP_EOL . OnArray::toString($this->store->getStore(STORE_SIP), ' = ', PHP_EOL, "'");
202
            $url = $this->createFormEditorUrl(FORM_NAME_FORM, $this->formSpec[F_ID]);
203

Carsten  Rose's avatar
Carsten Rose committed
204
205
206
            $buttonEditForm = $this->buildViewForm() .
                $this->buildShowEditFormElementCheckbox() .
                $this->buildButtonAnchor('form-edit-button', $url, $toolTip, GLYPH_ICON_TOOL);
207
208
209
        }

        // Button: Save
Carsten  Rose's avatar
Carsten Rose committed
210
        if (Support::findInSet(FORM_BUTTON_SAVE, $this->formSpec[F_SHOW_BUTTON]) && $this->formSpec[F_SUBMIT_BUTTON_TEXT] === '') {
211
212
213
            $toolTip = 'Save';

            if ($this->showDebugInfo) {
214
                $toolTip .= PHP_EOL . "table = '" . $this->formSpec[F_TABLE_NAME] . "'" . PHP_EOL . "r = '" . $recordId . "'";
215
216
            }

217
            $buttonSave = $this->buildButtonCode('save-button', $toolTip, GLYPH_ICON_CHECK, '', $this->formSpec[F_BUTTON_ON_CHANGE_CLASS]);
218
219
220
        }

        // Button: Close
Carsten  Rose's avatar
Carsten Rose committed
221
        if (Support::findInSet(FORM_BUTTON_CLOSE, $this->formSpec[F_SHOW_BUTTON])) {
222
223
            $toolTip = 'Close';

224
            $buttonClose = $this->buildButtonCode('close-button', 'Close', GLYPH_ICON_CLOSE);
Carsten  Rose's avatar
Carsten Rose committed
225
        }
226

Carsten  Rose's avatar
Carsten Rose committed
227
        // Button: Delete
Carsten  Rose's avatar
Carsten Rose committed
228
        if (Support::findInSet(FORM_BUTTON_DELETE, $this->formSpec[F_SHOW_BUTTON])) {
229
230
            $toolTip = 'Delete';

Carsten  Rose's avatar
Carsten Rose committed
231
            if ($this->showDebugInfo && $recordId > 0) {
232
                $toolTip .= PHP_EOL . "form = '" . $this->formSpec[F_FINAL_DELETE_FORM] . "'" . PHP_EOL . "r = '" . $recordId . "'";
Carsten  Rose's avatar
Carsten Rose committed
233
            }
234
            $disabled = ($recordId > 0) ? '' : 'disabled';
Carsten  Rose's avatar
Carsten Rose committed
235

236
            $buttonDelete = $this->buildButtonCode('delete-button', $toolTip, GLYPH_ICON_DELETE, $disabled);
237
238
        }

Carsten  Rose's avatar
Carsten Rose committed
239
        // Button: New
Carsten  Rose's avatar
Carsten Rose committed
240
        if (Support::findInSet(FORM_BUTTON_NEW, $this->formSpec[F_SHOW_BUTTON])) {
241
242
            $toolTip = 'New';
            $url = $this->deriveNewRecordUrlFromExistingSip($toolTip);
Carsten  Rose's avatar
Carsten Rose committed
243

244
            $buttonNew = $this->buildButtonAnchor('form-new-button', $url, $toolTip, GLYPH_ICON_NEW);
245
246
        }

247
        // Arrangement: Edit Form / Save / Close / Delete / New
Carsten  Rose's avatar
Carsten Rose committed
248
        // Specified in reverse order cause 'pull-right' inverts the order. http://getbootstrap.com/css/#helper-classes-floats
249
250
251
252
253
        $html = '';
        $html .= Support::wrapTag('<div class="btn-group pull-right" role="group">', $buttonNew);
        $html .= Support::wrapTag('<div class="btn-group pull-right" role="group">', $buttonDelete);
        $html .= Support::wrapTag('<div class="btn-group pull-right" role="group">', $buttonSave . $buttonClose);
        $html .= Support::wrapTag('<div class="btn-group pull-right" role="group">', $buttonEditForm);
254
255
256

        $html = Support::wrapTag('<div class="btn-toolbar" role="toolbar">', $html);

257
258
259
        return $html;
    }

260
    /**
Carsten  Rose's avatar
Carsten Rose committed
261
262
263
264
265
     * Generic function to create a button with a given id, $url, $title, $icon (=glyph), $disabled
     * @param string $id
     * @param string $url
     * @param string $title
     * @param string $icon
266
267
268
269
     * @param string $disabled
     * @return string
     */
    private function buildButtonAnchor($id, $url, $title, $icon, $disabled = '') {
Carsten  Rose's avatar
Carsten Rose committed
270
271
272
273
274
275
276
277
        $icon = Support::wrapTag("<span " . Support::doAttribute('class', "glyphicon $icon") . ">", '');

        $attribute = Support::doAttribute('href', $url);
        $attribute .= Support::doAttribute('id', $id);
        $attribute .= Support::doAttribute('class', "btn btn-default navbar-btn $disabled");
        $attribute .= Support::doAttribute('title', $title);

        return Support::wrapTag("<a $attribute>", $icon);
278
279
280
    }

    /**
281
282
     * Creates a button with the given attributes. If there is no $icon given, render the button without glyph.
     *
283
284
285
     * @param string $id
     * @param string $title
     * @param string $icon
286
287
288
     * @param string $disabled
     * @return string
     */
289
    private function buildButtonCode($id, $title, $icon, $disabled = '', $buttonOnChangeClass = '') {
290
291
292
293
294
295
296
297
298

        $element = "<span class='glyphicon $icon'></span>";
        $classAdd = "navbar-btn";

        if ($icon === '') {
            $element = $title;
            $classAdd = '';
        }

299
        $class = Support::doAttribute('class', ["btn btn-default", $classAdd]);
300
        $dataClassOnChange = Support::doAttribute('data-class-on-change', $buttonOnChangeClass);
301
        $title = Support::doAttribute('title', $title);
302
        return "<button id='$id' type='button' $class $dataClassOnChange $title $disabled>$element</button>";
303
304
    }

Carsten  Rose's avatar
Carsten Rose committed
305
    /**
306
     * @param $pillArray
Carsten  Rose's avatar
Carsten Rose committed
307
     * @return string
308
     * @throws UserFormException
Carsten  Rose's avatar
Carsten Rose committed
309
     */
310
311
312
    private function buildPillNavigation($pillArray) {
        $pillButton = '';
        $pillDropdown = '';
313
        $htmlDropdown = '';
314
315
316
317
318
319
320
321
322
323
324
325

        if ($pillArray == null)
            return '';

        $maxVisiblePill = (isset($this->formSpec['maxVisiblePill']) && $this->formSpec['maxVisiblePill'] !== '') ? $this->formSpec['maxVisiblePill'] : 1000;

        // Iterate over all 'pill'
        $ii = 0;
        $active = 'class="active"';
        foreach ($pillArray as $formElement) {
            $ii++;

326
            if ($formElement[FE_NAME] === '' || $formElement[FE_LABEL] === '') {
327
                $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($formElement), STORE_SYSTEM);
328
                $this->store->setVar(SYSTEM_FORM_ELEMENT_COLUMN, 'name, label', STORE_SYSTEM);
329
                throw new UserFormException("Field 'name' and/or 'label' are empty", ERROR_NAME_LABEL_EMPTY);
330
331
            }

332
            // Anker for pill navigation
333
            $a = '<a ' . Support::doAttribute('href', '#' . $this->createAnker($formElement['id'])) . ' data-toggle="tab">' . $formElement[FE_LABEL] . '</a>';
334

335
336
337
338
339
340
341
            if ($ii <= $maxVisiblePill) {
                $pillButton .= '<li role="presentation" ' . $active . '>' . $a . '</li>';
            } else {
                $pillDropdown .= '<li>' . $a . '</li>';
            }
            $active = '';
        }
342

343
344
        // Pill Dropdown necessary?
        if ($ii > $maxVisiblePill) {
345
            $htmlDropdown = Support::wrapTag('<ul class="dropdown-menu qfq-form-pill ' . $this->formSpec[F_CLASS_PILL] . '">', $pillDropdown, true);
346
            $htmlDropdown = '<a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button">more <span class="caret"></span></a>' . $htmlDropdown;
347
            $htmlDropdown = Support::wrapTag('<li role="presentation" class="dropdown">', $htmlDropdown, false);
348
        }
349

350
        $htmlDropdown = Support::wrapTag('<ul id="' . $this->getTabId() . '" class="nav nav-pills qfq-form-pill ' . $this->formSpec[F_CLASS_PILL] . '" role="tablist">', $pillButton . $htmlDropdown);
351
        $htmlDropdown = Support::wrapTag('<div class="col-md-12">', $htmlDropdown);
352

353
        return $htmlDropdown;
354
355
356
357
358
359
360
361
362
363
364
365
    }

    /**
     * Create an identifier for the pill navigation menu
     *
     * @param $id
     * @return string
     */
    private function createAnker($id) {
        return $this->formSpec['name'] . '_' . $id;
    }

Carsten  Rose's avatar
Carsten Rose committed
366
367
368
369
370
371
372
    /**
     * @return string
     */
    private function getTabId() {
        return 'qfqTabs';
    }

373
374
375
376
377
    /**
     * Builds the complete HTML '<form ...>'-tag
     *
     * @return string
     */
378
    public function getFormTag() {
379
380
381
382

        $attribute = $this->getFormTagAtrributes();

        $attribute['class'] = 'form-horizontal';
383
        $attribute['data-toggle'] = 'validator';
384
385
386
        if (isset($this->formSpec[F_SAVE_BUTTON_ACTIVE])) {
            $attribute[DATA_ENABLE_SAVE_BUTTON] = 'true';
        }
387
388
389
        return '<form ' . OnArray::toString($attribute, '=', ' ', "'") . '>';
    }

390
391
392
393
    /**
     * @return string
     */
    public function tail() {
394

395
        $html = '';
Carsten  Rose's avatar
Carsten Rose committed
396
        $deleteUrl = '';
397

398
399
        $formId = $this->getFormId();

400
401
        // Button Save at bottom of form - only if there is a button text given.
        if ($this->formSpec[F_SUBMIT_BUTTON_TEXT] !== '') {
402
403
404
405
406


            // Default setzen:
            $this->fillWrapLabelInputNote($this->formSpec[F_BS_LABEL_COLUMNS], $this->formSpec[F_BS_INPUT_COLUMNS], $this->formSpec[F_BS_NOTE_COLUMNS]);

407
408
            $buttonText = $this->formSpec[F_SUBMIT_BUTTON_TEXT];

409
            $htmlElement = $this->buildButtonCode('save-button', $buttonText, '', '', $this->formSpec[F_BUTTON_ON_CHANGE_CLASS]);
410
411
412
413
414
415
416
417

            $html .= $this->wrapItem(WRAP_SETUP_LABEL, '');
            $html .= $this->wrapItem(WRAP_SETUP_INPUT, $htmlElement);
            $html .= $this->wrapItem(WRAP_SETUP_NOTE, '');

            $html = $this->wrapItem(WRAP_SETUP_ELEMENT, $html);
        }

418
        $html .= '</div> <!--class="tab-content" -->';  //  <div class="tab-content">
419
//        $html .= '<input type="submit" value="Submit">';
420

Carsten  Rose's avatar
Carsten Rose committed
421
422
423
        $formId = $this->getFormId();
        $tabId = $this->getTabId();

Carsten  Rose's avatar
Carsten Rose committed
424
        if (0 < ($recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP))) {
425
            $deleteUrl = $this->createDeleteUrl($this->formSpec[F_FINAL_DELETE_FORM], '', $recordId);
Carsten  Rose's avatar
Carsten Rose committed
426
        }
427

428
429
430
        $actionUpload = FILE_ACTION . '=' . FILE_ACTION_UPLOAD;
        $actionDelete = FILE_ACTION . '=' . FILE_ACTION_DELETE;

431
432
433
        $apiDir = API_DIR;
        $apiDeletePhp = API_DIR . '/' . API_DELETE_PHP;

434
        $html .= '</form>';  //  <form class="form-horizontal" ...
435
436
437
438
439
440
        $html .= <<<EOF
        <script type="text/javascript">
            $(function () {
                'use strict';
                QfqNS.Log.level = 0;

Carsten  Rose's avatar
Carsten Rose committed
441
442
443
                var qfqPage = new QfqNS.QfqPage({
                    tabsId: '$tabId',
                    formId: '$formId',
444
                    submitTo: '$apiDir/save.php',
Carsten  Rose's avatar
Carsten Rose committed
445
                    deleteUrl: '$deleteUrl',
446
447
448
                    refreshUrl: '$apiDir/load.php',
                    fileUploadTo: '$apiDir/file.php?$actionUpload',
                    fileDeleteUrl: '$apiDir/file.php?$actionDelete'
Carsten  Rose's avatar
Carsten Rose committed
449
450
                });

451
                var qfqRecordList = new QfqNS.QfqRecordList('$apiDeletePhp');
Carsten  Rose's avatar
Carsten Rose committed
452
            })
453
454
         </script>
EOF;
455
        $html .= '</div>';  //  <div class="container-fluid"> === main <div class=...> around everything
456

457
458
459
460
461
        return $html;
    }

    /**
     * @param array $formElement
462
     * @param $htmlFormElementName
463
464
465
     * @param $value
     * @return mixed
     */
466
    public function buildPill(array $formElement, $htmlFormElementName, $value, array &$json) {
467
        $html = '';
468
469
470
471
        // save parent processed FE's
        $tmpStore = $this->feSpecNative;

        // child FE's
472
473
474
        $this->feSpecNative = $this->db->getNativeFormElements(SQL_FORM_ELEMENT_SPECIFIC_CONTAINER,
            ['yes', $this->formSpec["id"], 'native,container', $formElement['id']], $this->formSpec);

Carsten  Rose's avatar
Carsten Rose committed
475
        $html = $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_NATIVE_SUBRECORD, 0, $json);
476
477
478
479

        // restore parent processed FE's
        $this->feSpecNative = $tmpStore;

480
481
482
        return $html;
    }

483
    /**
484
485
     * @param array $formElement Complete FormElement, especially some FE_WRAP
     * @param string $htmlElement Content to wrap.
486
     * @param $htmlFormElementName
487
     * @return string               Wrapped $htmlElement
488
     * @throws \qfq\UserFormException
489
     */
490
    public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementName) {
491
        $html = '';
492
        $htmlLabel = '';
493

Carsten  Rose's avatar
Carsten Rose committed
494
        // Label
495
        if ($formElement[FE_BS_LABEL_COLUMNS] > 0) {
496
            $htmlLabel = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL]);
497
        }
498

499
        $html .= $this->customWrap($formElement, $htmlLabel, FE_WRAP_LABEL, $formElement[FE_BS_LABEL_COLUMNS],
500
            [$this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_START], $this->wrap[WRAP_SETUP_LABEL][WRAP_SETUP_END]], $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_LABEL);
501

Carsten  Rose's avatar
Carsten Rose committed
502
        // Input
503
        $html .= $this->customWrap($formElement, $htmlElement, FE_WRAP_INPUT, $formElement[FE_BS_INPUT_COLUMNS],
504
            [$this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_START], $this->wrap[WRAP_SETUP_INPUT][WRAP_SETUP_END]], $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_INPUT);
505

Carsten  Rose's avatar
Carsten Rose committed
506
        // Note
Carsten  Rose's avatar
Carsten Rose committed
507
        $note = $formElement[FE_NOTE];
508
        $html .= $this->customWrap($formElement, $note, FE_WRAP_NOTE, $formElement[FE_BS_NOTE_COLUMNS],
509
            [$this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_START], $this->wrap[WRAP_SETUP_NOTE][WRAP_SETUP_END]], $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_NOTE);
510
511
512
513

        // ROW
        $openTag = (Support::findInSet('row', $formElement[FE_WRAP_ROW_LABEL_INPUT_NOW])) ? $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_START] : '';
        $closeTag = (Support::findInSet('/row', $formElement[FE_WRAP_ROW_LABEL_INPUT_NOW])) ? $this->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_END] : '';
514
        $html = $this->customWrap($formElement, $html, FE_WRAP_ROW, 99, [$openTag, $closeTag], $formElement[FE_HTML_ID] . HTML_ID_EXTENSION_ROW);
515
516
517
518

        return $html;
    }

519
    /**
520
521
522
523
     *
     * @param array $formElement Complete FormElement, especially some FE_WRAP
     * @param string $htmlElement Content to wrap.
     * @param string $wrapName FE_WRAP_ROW, FE_WRAP_LABEL, FE_WRAP_INPUT, FE_WRAP_NOTE
524
     * @param int $bsColumns
525
     * @param array $wrapArray Systemwide Defaults: [ 'open wrap', 'close wrap' ]
526
     * @return string Wrapped $htmlElement
527
528
     * @throws \qfq\UserFormException
     */
529
    private function customWrap(array $formElement, $htmlElement, $wrapName, $bsColumns, array $wrapArray, $htmlId = '') {
530

531
        // If $bsColumns==0: do not wrap with default.
532
533
534
535
        if ($bsColumns == 0) {
            $wrapArray[0] = '';
            $wrapArray[1] = '';
        }
536

537
        // If there is a 'per FormElement'-wrap, take it.
538
539
540
541
542
543
544
545
        if (isset($formElement[$wrapName])) {
            $wrapArray = explode('|', $formElement[$wrapName], 2);
        }

        if (count($wrapArray) != 2) {
            throw new UserFormException("Need open & close wrap token for FormElement.parameter" . $wrapName . " - E.g.: <div ...>|</div>", ERROR_MISSING_VALUE);
        }

546
547
548
549
        if ($wrapArray[0] != '') {
            $wrapArray[0] = Support::insertAttribute($wrapArray[0], 'id', $htmlId);
        }

550
551
552
        return $wrapArray[0] . $htmlElement . $wrapArray[1];
    }

553
554
555
556
557
    /**
     * @param $formElement
     * @param $elementHtml
     * @return string
     */
558
    public function buildRowPill(array $formElement, $elementHtml) {
559
560
        $html = '';

561
        $html .= Support::wrapTag('<div class="col-md-12 qfq-form-body ' . $this->formSpec[F_CLASS_BODY] . '">', $elementHtml);
562
563
564

        $active = $this->isFirstPill ? ' active' : '';

565
        $html = Support::wrapTag('<div role="tabpanel" class="tab-pane' . $active . '" id="' . $this->createAnker($formElement['id']) . '">', $html);
566
567
568
569
570
571

        $this->isFirstPill = false;

        return $html;
    }

572
    /**
573
574
     * Builds a fieldset
     *
575
576
577
     * @param $formElement
     * @param $elementHtml
     */
578
    public function buildRowFieldset(array $formElement, $elementHtml) {
579
580
581
        $html = $elementHtml;

        return $html;
582
583
    }

584
585
586
587
588
589
590
591
592
593
594
595
    /**
     * Builds a templateGroup
     *
     * @param $formElement
     * @param $elementHtml
     */
    public function buildRowTemplateGroup(array $formElement, $elementHtml) {
        $html = $elementHtml;

        return $html;
    }

596
597
598
599
600
    /**
     * @param $formElement
     * @param $elementHtml
     * @return string
     */
601
    public function buildRowSubrecord(array $formElement, $elementHtml) {
602
        $html = '';
603
        $html .= $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $formElement[FE_LABEL]));
604
        $html .= $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $elementHtml));
605
        $html .= $this->wrapItem(WRAP_SETUP_ELEMENT, $this->wrapItem(WRAP_SETUP_SUBRECORD, $formElement[FE_NOTE]));
606
607
608

        return $html;
    }
609
}