Test Setup Failed
Push — master ( 194661...f85b2d )
by Stefan
06:51
created

OptionDisplay::addOptionEdit()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 20
rs 8.8333
c 0
b 0
f 0
cc 7
nc 6
nop 2
1
<?php
2
3
/*
4
 * *****************************************************************************
5
 * Contributions to this work were made on behalf of the GÉANT project, a 
6
 * project that has received funding from the European Union’s Framework 
7
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
8
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
9
 * 691567 (GN4-1) and No. 731122 (GN4-2).
10
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
11
 * of the copyright in all material which was developed by a member of the GÉANT
12
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
13
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
14
 * UK as a branch of GÉANT Vereniging.
15
 * 
16
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
17
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
18
 *
19
 * License: see the web/copyright.inc.php file in the file structure or
20
 *          <base_url>/copyright.php after deploying the software
21
 */
22
23
namespace web\lib\admin;
24
25
use Exception;
26
27
/**
28
 * We need to display previously set options in various forms. This class covers
29
 * the ways to do that; the generated page content can then be parsed with 
30
 * OptionParser.
31
 * 
32
 * @author Stefan Winter <[email protected]>
33
 */
34
class OptionDisplay extends \core\common\Entity
35
{
36
37
    /**
38
     * stores all the options we are caring about
39
     * 
40
     * @var array
41
     */
42
    private $listOfOptions;
43
44
    /**
45
     * on which level are we operating?
46
     * 
47
     * @var string
48
     */
49
    private $level;
50
51
    /**
52
     * a counter storing how many locations are to be displayed
53
     * 
54
     * @var integer
55
     */
56
    private $allLocationCount;
57
58
    /**
59
     * When "fresh" options are displayed (HTML select/otion fields, optionally
60
     * with language, and of varying data types) we want to give each option
61
     * the same prominence and iterate over all options in the list. This
62
     * variable keeps track how many option HTML code we've already sent, so
63
     * that we can iterate correctly.
64
     * 
65
     * Only used inside noPrefillText variant of the optiontext() call
66
     * 
67
     * @var integer
68
     */
69
    private $optionIterator;
70
71
    private $htmlDatatypeTexts;
72
    
73
    private $enumPrettyPrints;
74
    /**
75
     * Which attributes are we talking about?
76
     * @param array  $options the options of interest
77
     * @param string $level   the level on which these options were defined by the user (not applicable for XHR UI, then it is NULL)
78
     */
79
    public function __construct(array $options, string $level = NULL)
80
    {
81
        $this->listOfOptions = $options;
82
        $this->level = $level;
83
        $this->allLocationCount = 0;
84
85
        $this->enumPrettyPrints = [
86
            "ask" => _("Ask User"),
87
            "always" => _("Always"),
88
        ];
89
        
90
        $this->htmlDatatypeTexts = [
91
            \core\Options::TYPECODE_FILE => ["html" => "input type='file'", "tail" => ' size=\'10\''],
92
            \core\Options::TYPECODE_BOOLEAN => ["html" => "input type='checkbox'", "tail" => ''],
93
            \core\Options::TYPECODE_INTEGER => ["html" => "input type='number'", "tail" => ''],
94
            \core\Options::TYPECODE_STRING => ["html" => "input type='string'", "tail" => ''],
95
            \core\Options::TYPECODE_ENUM_OPENROAMING => ["html" => "select", "tail" => "><option value='ask'>" . $this->enumPrettyPrints["ask"]  . "</option><option value='always'>" . $this->enumPrettyPrints["always"] . "</option></select"],
96
            \core\Options::TYPECODE_TEXT => ["html" => "textarea cols='30' rows='3'", "tail" => '></textarea'],
97
        ];
98
    }
99
100
    /**
101
     * creates a table with all the set options prefilled. Only displays options
102
     * of the category indicated.
103
     * @param string $attributePrefix category of option to display
104
     * @param string $fed             the federation we are in
105
     * @return string HTML code <table>
106
     */
107
    public function prefilledOptionTable(string $attributePrefix, $fed)
108
    {
109
        $retval = "<table id='expandable_$attributePrefix" . "_options'>";
110
111
        $prepopulate = [];
112
        foreach ($this->listOfOptions as $existingAttribute) {
113
            if ($existingAttribute['level'] == $this->level) {
114
                $prepopulate[] = $existingAttribute;
115
            }
116
        }
117
        if (is_array($prepopulate) && ( count($prepopulate) > 0 || $attributePrefix == "device-specific" || $attributePrefix == "eap-specific" )) { // editing... fill with values
118
            $retval .= $this->addOptionEdit($attributePrefix, $prepopulate);
119
        } else {
120
            $retval .= $this->addOptionNew($attributePrefix, $fed);
121
        }
122
        $retval .= "</table>";
123
        return $retval;
124
    }
125
126
    /**
127
     * Displays options for a given option class, in Edit mode.
128
     * 
129
     * @param string $class       the class of options that is to be displayed
130
     * @param array  $prepopulate should an empty set of fillable options be displayed, or do we have existing data to prefill with
131
     * @return string
132
     */
133
    private function addOptionEdit(string $class, array $prepopulate = [])
134
    { // no GET class ? we've been called directly:
135
        // this can mean either a new object (list all options with empty values)
136
        // or that an object is to be edited. In that case, $prepopulated has to
137
        // contain the array of existing variables
138
        // we expect the variable $class to contain the class of options
139
        $retval = "";
140
        $optioninfo = \core\Options::instance();
141
        $blackListOnPrefill = "user:fedadmin|managedsp:vlan|managedsp:operatorname";
142
        if (\config\Master::FUNCTIONALITY_LOCATIONS['CONFASSISTANT_SILVERBULLET'] == "LOCAL" && \config\Master::FUNCTIONALITY_LOCATIONS['CONFASSISTANT_RADIUS'] != "LOCAL") {
143
            $blackListOnPrefill .= "|fed:silverbullet";
144
        }
145
        foreach ($prepopulate as $option) {
146
            if (preg_match("/$class:/", $option['name']) && !preg_match("/($blackListOnPrefill)/", $option['name'])) {
147
                $optiontypearray = $optioninfo->optionType($option['name']);
148
                $loggerInstance = new \core\common\Logging();
149
                $loggerInstance->debug(5, "About to execute optiontext with PREFILL!\n");
150
                $retval .= $this->optiontext([$option['name']], ($optiontypearray["type"] == "file" ? 'ROWID-' . $option['level'] . '-' . $option['row'] : $option['value']), $option['lang']);
151
            }
152
        }
153
        return $retval;
154
    }
155
156
    /**
157
     * Find which options to expose to UI and which to hide.
158
     * Not all options defined in the database are (always) displayed. Some have
159
     * custom UI not matching the usual dropdown display, some depend on context
160
     * (e.g. OpenRoaming or not, depending on whether the fed operator wants it
161
     * 
162
     * @param string $class the type of options requested
163
     * @param string $fed   the federation TLD, to determine fed ops prefernce context
164
     * @return array the list of options to display
165
     */
166
    public static function enumerateOptionsToDisplay($class, $fed)
167
    {
168
        $optioninfo = \core\Options::instance();
169
170
        $list = $optioninfo->availableOptions($class);
171
172
        // use federation context to delete more options, if the feds don't like
173
        // a particular one
174
        $fedInstance = new \core\Federation($fed);
175
        switch ($class) {
176
            case "general":
177
                unset($list[array_search("general:geo_coordinates", $list)]);
178
                break;
179
            case "user":
180
                unset($list[array_search("user:fedadmin", $list)]);
181
                break;
182
            case "managedsp":
183
                unset($list[array_search("managedsp:vlan", $list)]);
184
                unset($list[array_search("managedsp:operatorname", $list)]);
185
                break;
186
            case "fed":
187
                //normally, we have nothing to hide on that level
188
                // if we are a Managed IdP exclusive deployment, do not display or allow
189
                // to change the "Enable Managed IdP" boolean - it is simply always there
190
                if (\config\Master::FUNCTIONALITY_LOCATIONS['CONFASSISTANT_SILVERBULLET'] == "LOCAL" && \config\Master::FUNCTIONALITY_LOCATIONS['CONFASSISTANT_RADIUS'] != "LOCAL") {
191
                    unset($list[array_search("fed:silverbullet", $list)]);
192
                }
193
                break;
194
            case "media":
195
                if ($fedInstance->getAttributes("fed:openroaming") == []) {
196
                    // no openroaming here
197
                    unset($list[array_search("media:openroaming_always", $list)]);
198
                    unset($list[array_search("media:openroaming_ask", $list)]);
199
                    unset($list[array_search("media:openroaming", $list)]);
200
                }
201
                break;
202
            default:
203
                break;
204
        }
205
206
        return $list;
207
    }
208
209
    /**
210
     * Displays options for a given option class, in New mode.
211
     * 
212
     * @param string $class           the class of options that is to be displayed
213
     * @param string $fed             the federation we are in
214
     * @return string
215
     */
216
    private function addOptionNew(string $class, $fed)
217
    {
218
        $retval = "";
219
220
        $list2 = array_values(OptionDisplay::enumerateOptionsToDisplay($class, $fed));
221
222
        // add as many options as there are different option types
223
        $numberOfOptions = count($list2);
224
        for ($this->optionIterator = 0; $this->optionIterator < $numberOfOptions; $this->optionIterator++) {
225
            $retval .= $this->optiontext($list2);
226
        }
227
        return $retval;
228
    }
229
230
    /**
231
     * produce code for a option-specific tooltip
232
     * @param int     $rowid     the number (nonce during page build) of the option 
233
     *                           that should get the tooltip
234
     * @param string  $input     the option name. Tooltip for it will be displayed
235
     *                           if we have one available.
236
     * @param boolean $isVisible should the tooltip be visible with the option,
237
     *                           or are they both currently hidden?
238
     * @return string
239
     */
240
    private function tooltip($rowid, $input, $isVisible)
241
    {
242
        \core\common\Entity::intoThePotatoes();
243
        $descriptions = [];
244
        if (count(\config\ConfAssistant::CONSORTIUM['ssid']) > 0) {
245
            $descriptions["media:SSID"] = sprintf(_("This attribute can be set if you want to configure an additional SSID besides the default SSIDs for %s. It is almost always a bad idea not to use the default SSIDs. The only exception is if you have premises with an overlap of the radio signal with another %s hotspot. Typical misconceptions about additional SSIDs include: I want to have a local SSID for my own users. It is much better to use the default SSID and separate user groups with VLANs. That approach has two advantages: 1) your users will configure %s properly because it is their everyday SSID; 2) if you use a custom name and advertise this one as extra secure, your users might at some point roam to another place which happens to have the same SSID name. They might then be misled to believe that they are connecting to an extra secure network while they are not."), \config\ConfAssistant::CONSORTIUM['display_name'], \config\ConfAssistant::CONSORTIUM['display_name'], \config\ConfAssistant::CONSORTIUM['display_name']);
246
        }
247
        $descriptions["media:force_proxy"] = sprintf(_("The format of this option is: IPv4|IPv6|hostname:port . Forcing your users through a content filter of your own is a significant invasion of user self-determination. It also has technical issues. Please throughly read the discussion at %s before specifying a proxy with this option. This feature is currently experimental and only has an effect in Apple installers."), "https://github.com/GEANT/CAT/issues/96");
248
        $descriptions["managedsp:realmforvlan"] = sprintf(_("If you are also using %s, then your own realm is automatically tagged with the VLAN you choose, there is no need to add it here manually."), \core\ProfileSilverbullet::PRODUCTNAME);
249
        $descriptions["media:openroaming"] = sprintf(_("By opting in to OpenRoaming, you agree to be bound by the %s."), "eduroam Ecosystem Broker OpenRoaming Identity Provider Policy") .
250
                " " .
251
                sprintf(_("Note that your requirement to inform users about the OpenRoaming End User Terms and Conditions is fulfilled when directing your end users to the %s download portal for installer download. Any other means of providing the installers needs to present this information via its own channel."), \config\Master::APPEARANCE['productname']) .
252
                " " .
253
                _("You are also aware that for best technical interoperability, you need to add a DNS entry into the DNS zone of your RADIUS realm.") .
254
                " " .
255
                _("Read the instructions in the wiki.");
256
        \core\common\Entity::outOfThePotatoes();
257
        if (!isset($descriptions[$input])) {
258
            return "";
259
        }
260
        return "<span class='tooltip' id='S$rowid-tooltip-$input' style='display:" . ($isVisible ? "block" : "none") . "' onclick='alert(\"" . $descriptions[$input] . "\")'><img src='../resources/images/icons/question-mark-icon.png" . "'></span>";
261
    }
262
263
    /**
264
     * 
265
     * @param int   $rowid the number (nonce during page build) of the option 
266
     *                     that should get the tooltip
267
     * @param array $list  elements of the drop-down list
268
     * @return array HTML code and which option is active
269
     * @throws \Exception
270
     */
271
    private function selectElement($rowid, $list)
272
    {
273
        $jsmagic = "onchange='
274
                               if (/#ML#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) {
275
                                   document.getElementById(\"S$rowid-input-langselect\").style.display = \"block\";
276
                                   } else {
277
                                   document.getElementById(\"S$rowid-input-langselect\").style.display = \"none\";
278
                                   }";
279
        foreach (array_keys($this->htmlDatatypeTexts) as $key) {
280
            $jsmagic .= "if (/#" . $key . "#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) {
281
                                  document.getElementById(\"S$rowid-input-file\").style.display = \"" . ($key == \core\Options::TYPECODE_FILE ? "block" : "none") . "\";
282
                                  document.getElementById(\"S$rowid-input-text\").style.display = \"" . ($key == \core\Options::TYPECODE_TEXT ? "block" : "none") . "\";
283
                                  document.getElementById(\"S$rowid-input-string\").style.display = \"" . ($key == \core\Options::TYPECODE_STRING ? "block" : "none") . "\";
284
                                  document.getElementById(\"S$rowid-input-enum_openroaming\").style.display = \"" . ($key == \core\Options::TYPECODE_ENUM_OPENROAMING ? "block" : "none") . "\";
285
                                  document.getElementById(\"S$rowid-input-boolean\").style.display = \"" . ($key == \core\Options::TYPECODE_BOOLEAN ? "block" : "none") . "\";
286
                                  document.getElementById(\"S$rowid-input-integer\").style.display = \"" . ($key == \core\Options::TYPECODE_INTEGER ? "block" : "none") . "\";
287
                             }
288
                             ";
289
            // hide all tooltips (each is a <span>, and there are no other <span>s)
290
            $jsmagic .= <<< FOO
291
                    var ourtooltips = document.querySelectorAll(&#34;[id^=&#39;S$rowid-tooltip-&#39;]&#34;);
292
                    for (var i=0; i<ourtooltips.length; i++) {
293
                      ourtooltips[i].style.display = "none";
294
                    }
295
                    var optionnamefull = document.getElementById("option-S$rowid-select").value;
296
                    var firstdelimiter = optionnamefull.indexOf("#");
297
                    var optionname = optionnamefull.substring(0,firstdelimiter);
298
                    var tooltipifany = document.getElementById("S$rowid-tooltip-"+optionname);
299
                    if (tooltipifany != null) {
300
                      tooltipifany.style.display = "block";
301
                    }
302
FOO;
303
        }
304
        $jsmagic .= "'";
305
306
        $optioninfo = \core\Options::instance();
307
        $retval = "<span style='display:flex';>";
308
        $iterator = 0;
309
        $tooltips = "";
310
        $uiElements = new UIElements();
311
        $activelisttype = [];
312
        switch (count($list)) {
313
            case 1: // if there is only one option available, don't introduce an artificial drop-down for it
314
                $value = array_shift($list);
315
                $listtype = $optioninfo->optionType($value);
316
                $retval .= $uiElements->displayName($value);
317
                $retval .= "<input type='hidden' name='option[S$rowid]' value='$value#" . $listtype["type"] . "#" . $listtype["flag"] . "#'/>";
318
                $activelisttype = $listtype;
319
                $tooltips = $this->tooltip($rowid, $value, TRUE);
320
                break;
321
            default:
322
                $retval .= "<select id='option-S$rowid-select' name='option[S$rowid]' $jsmagic>";
323
                foreach ($list as $value) {
324
                    $listtype = $optioninfo->optionType($value);
325
                    $retval .= "<option id='option-S$rowid-v-$value' value='$value#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ";
326
                    if ($iterator == $this->optionIterator) {
327
                        $retval .= "selected='selected'";
328
                        $activelisttype = $listtype;
329
                        $tooltips .= $this->tooltip($rowid, $value, TRUE);
330
                    } else {
331
                        $tooltips .= $this->tooltip($rowid, $value, FALSE);
332
                    }
333
                    $retval .= ">" . $uiElements->displayName($value) . "</option>";
334
                    $iterator++;
335
                }
336
337
                if (count($activelisttype) == 0) {
338
                    throw new \Exception("We should have found the active list type by now!");
339
                }
340
                $retval .= "</select>";
341
        }
342
        $retval .= $tooltips;
343
        $retval .= "</span>";
344
345
        return ["TEXT" => $retval, "ACTIVE" => $activelisttype];
346
    }
347
348
    /**
349
     * HTML code to display the language selector
350
     * 
351
     * @param int     $rowid       the number (nonce during page build) of the option 
352
     *                             that should get the tooltip
353
     * @param boolean $makeVisible is the language selector to be made visible?
354
     * @return string
355
     */
356
    private function selectLanguage($rowid, $makeVisible)
357
    {
358
        \core\common\Entity::intoThePotatoes();
359
        $retval = "<select style='display:" . ($makeVisible ? "block" : "none") . "' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect'>
360
            <option value='' name='select_language' selected>" . _("select language") . "</option>
361
            <option value='C' name='all_languages'>" . _("default/other languages") . "</option>";
362
        foreach (\config\Master::LANGUAGES as $langindex => $possibleLang) {
363
            $thislang = $possibleLang['display'];
364
            $retval .= "<option value='$langindex' name='$langindex'>$thislang</option>";
365
        }
366
        $retval .= "</select>";
367
        \core\common\Entity::outOfThePotatoes();
368
        return $retval;
369
    }
370
371
    /**
372
     * HTML code for a given option. Marks the matching datatype as visible, all other datatypes hidden
373
     * @param int   $rowid      the number (nonce during page build) of the option 
374
     *                          that should get the tooltip
375
     * @param array $activetype the active datatype that is to be visible
376
     * @return string
377
     */
378
    private function inputFields($rowid, $activetype)
379
    {
380
        $retval = "";
381
        foreach ($this->htmlDatatypeTexts as $key => $type) {
382
            $retval .= "<" . $type['html'] . " style='display:" . ($activetype['type'] == $key ? "block" : "none") . "' name='value[S$rowid-$key]' id='S" . $rowid . "-input-" . $key . "'" . $type['tail'] . ">";
383
        }
384
        return $retval;
385
    }
386
387
    /**
388
     * HTML code to display a "fresh" option (including type selector and JavaScript to show/hide relevant input fields)
389
     * @param int   $rowid the HTML field base name of the option to be displayed
390
     * @param array $list  the list of option names to include in the type selector
391
     * @return string HTML code
392
     * @throws Exception
393
     */
394
    private function noPrefillText(int $rowid, array $list)
395
    {
396
        // first column: the <select> element with the names of options and their field-toggling JS magic
397
        $selectorInfo = $this->selectElement($rowid, $list);
398
        $retval = "<td>" . $selectorInfo["TEXT"] . "</td>";
399
        // second column: the <select> element for language selection - only visible if the active option is multi-lang
400
        $retval .= "<td>" . $this->selectLanguage($rowid, $selectorInfo['ACTIVE']['flag'] == "ML") . "</td>";
401
        // third column: the actual input fields; the data type of the active option is visible, all others hidden
402
        $retval .= "<td>" . $this->inputFields($rowid, $selectorInfo['ACTIVE']) . "</td>";
403
        return $retval;
404
    }
405
406
    /**
407
     * generates HTML code that displays an already set option.
408
     * 
409
     * @param int    $rowid       the HTML field base name of the option to be displayed
410
     * @param string $optionName  the name of the option to display
411
     * @param string $optionValue the value of the option to display
412
     * @param mixed  $optionLang  the language of the option to display
413
     * @return string HTML code
414
     * @throws Exception
415
     */
416
    private function prefillText(int $rowid, string $optionName, string $optionValue, $optionLang)
417
    {
418
        \core\common\Entity::intoThePotatoes();
419
        $retval = "";
420
        $optioninfo = \core\Options::instance();
421
        $loggerInstance = new \core\common\Logging();
422
        $loggerInstance->debug(5, "Executed with PREFILL $optionValue!\n");
423
        $retval .= "<td>";
424
        $uiElements = new UIElements();
425
        $listtype = $optioninfo->optionType($optionName);
426
        $retval .= "<span style='display:flex;'>" . $uiElements->displayName($optionName);
427
        $retval .= $this->tooltip($rowid, $optionName, TRUE) . "</span>";
428
        $retval .= "<input type='hidden' id='option-S$rowid-select' name='option[S$rowid]' value='$optionName#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ></td>";
429
430
        // language tag if any
431
        $retval .= "<td>";
432
        if ($listtype["flag"] == "ML") {
433
434
            $language = "(" . strtoupper($optionLang) . ")";
435
            if ($optionLang == 'C') {
436
                $language = _("(default/other languages)");
437
            }
438
            $retval .= $language;
439
            $retval .= "<input type='hidden' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect' value='" . $optionLang . "' style='display:block'>";
440
        }
441
        $retval .= "</td>";
442
// attribute content
443
        $retval .= "<td>";
444
        $displayedVariant = "";
445
        switch ($listtype["type"]) {
446
            case \core\Options::TYPECODE_COORDINATES:
447
                $this->allLocationCount = $this->allLocationCount + 1;
448
                // display of the locations varies by map provider
449
                $classname = "\web\lib\admin\Map" . \config\ConfAssistant::MAPPROVIDER['PROVIDER'];
450
                $link = $classname::optionListDisplayCode($optionValue, $this->allLocationCount);
451
                $retval .= "<input readonly style='display:none' type='text' name='value[S$rowid-" . \core\Options::TYPECODE_TEXT . "]' id='S$rowid-input-text' value='$optionValue'>$link";
452
                break;
453
            case \core\Options::TYPECODE_FILE:
454
                $retval .= "<input readonly type='text' name='value[S$rowid-" . \core\Options::TYPECODE_STRING . "]' id='S" . $rowid . "-input-string' style='display:none' value='" . urlencode($optionValue) . "'>";
455
                $uiElements = new UIElements();
456
                switch ($optionName) {
457
                    case "eap:ca_file":
458
                    // fall-through intentional: display both types the same way
459
                    case "fed:minted_ca_file":
460
                        $retval .= $uiElements->previewCAinHTML($optionValue);
461
                        break;
462
                    case "general:logo_file":
463
                    // fall-through intentional: display both types the same way
464
                    case "fed:logo_file":
465
                        $retval .= $uiElements->previewImageinHTML($optionValue);
466
                        break;
467
                    case "support:info_file":
468
                        $retval .= $uiElements->previewInfoFileinHTML($optionValue);
469
                        break;
470
                    default:
471
                        $retval .= _("file content");
472
                }
473
                break;
474
            case \core\Options::TYPECODE_ENUM_OPENROAMING: // is a string after all
475
                $displayedVariant = $this->enumPrettyPrints[$optionValue];
476
                $retval .= "<strong>$displayedVariant</strong><input type='hidden' name='value[S$rowid-" . $listtype['type'] . "]' id='S" . $rowid . "-input-" . $listtype["type"] . "' value=\"" . htmlspecialchars($optionValue) . "\" style='display:block'>";
477
                break;
478
            case \core\Options::TYPECODE_STRING:
479
            // fall-thorugh is intentional; mostly identical HTML code for the three types
480
            case \core\Options::TYPECODE_INTEGER:
481
            // fall-thorugh is intentional; mostly identical HTML code for the three types
482
            case \core\Options::TYPECODE_TEXT:
483
                $displayedVariant = $optionValue; // for all three types, value tag and actual display are identical
484
                $retval .= "<strong>$displayedVariant</strong><input type='hidden' name='value[S$rowid-" . $listtype['type'] . "]' id='S" . $rowid . "-input-" . $listtype["type"] . "' value=\"" . htmlspecialchars($optionValue) . "\" style='display:block'>";
485
                break;
486
            case \core\Options::TYPECODE_BOOLEAN:
487
                $displayedVariant = ($optionValue == "on" ? _("on") : _("off"));
488
                $retval .= "<strong>$displayedVariant</strong><input type='hidden' name='value[S$rowid-" . $listtype['type'] . "]' id='S" . $rowid . "-input-" . $listtype["type"] . "' value=\"" . htmlspecialchars($optionValue) . "\" style='display:block'>";
489
                break;
490
            default:
491
                // this should never happen!
492
                throw new Exception("Internal Error: unknown attribute type $listtype!");
493
        }
494
        $retval .= "</td>";
495
        \core\common\Entity::outOfThePotatoes();
496
        return $retval;
497
    }
498
499
    /**
500
     * Displays a container for options. Either with prefilled data or empty; if
501
     * empty then has HTML <input> tags with clever javaScript to allow selection
502
     * of different option names and types
503
     * @param array  $list         options which should be displayed; can be only exactly one if existing option, or multiple if new option type
504
     * @param string $prefillValue for an existing option, it's value to be displayed
505
     * @param string $prefillLang  for an existing option, the language of the value to be displayed
506
     * @return string HTML code <tr>
507
     * @throws Exception
508
     */
509
    public function optiontext(array $list, string $prefillValue = NULL, string $prefillLang = NULL)
510
    {
511
        $rowid = mt_rand();
512
513
        $retval = "<tr id='option-S$rowid' style='vertical-align:top'>";
514
515
        $item = "MULTIPLE";
516
        if ($prefillValue === NULL) {
517
            $retval .= $this->noPrefillText($rowid, $list);
518
        }
519
520
        if ($prefillValue !== NULL) {
521
            // prefill is always only called with a list with exactly one element.
522
            // if we see anything else here, get excited.
523
            if (count($list) != 1) {
524
                throw new Exception("Optiontext prefilled display only can work with exactly one option!");
525
            }
526
            $item = array_pop($list);
527
            $retval .= $this->prefillText($rowid, $item, $prefillValue, $prefillLang);
528
        }
529
        $retval .= "
530
531
       <td>
532
          <button type='button' class='delete' onclick='";
533
        if ($prefillValue !== NULL && $item == "general:geo_coordinates") {
534
            $funcname = "Map" . \config\ConfAssistant::MAPPROVIDER['PROVIDER'] . 'DeleteCoord';
535
            $retval .= 'if (typeof ' . $funcname . ' === "function") { ' . $funcname . '(' . $this->allLocationCount . '); } ';
536
        }
537
        $retval .= 'deleteOption("option-S' . $rowid . '")';
538
        $retval .= "'>-</button>
539
       </td>
540
    </tr>";
541
        return $retval;
542
    }
543
}