OptionDisplay::__construct()   B
last analyzed

Complexity

Conditions 7
Paths 12

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 26
c 1
b 0
f 0
dl 0
loc 35
rs 8.5706
cc 7
nc 12
nop 3
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/option 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, $wizardStyle = false)
80
    {
81
        $this->listOfOptions = $options;
82
        $this->level = $level;
83
        $this->allLocationCount = 0;
84
        if ($level === \core\Options::LEVEL_PROFILE || $level === \core\Options::LEVEL_IDP) {
85
            $this->enumPrettyPrints = [
86
                "ask" => _("Ask User"),
87
                "ask-preagreed" => _("Ask User; T&C Pre-Agreed"),
88
                "always" => _("Always"),
89
                "always-preagreed" => _("Always; T&C Pre-Agreed"),
90
            ];
91
        } elseif ($level === \core\Options::LEVEL_FED || $level === \core\Options::LEVEL_IDP) {
92
            $this->enumPrettyPrints = [
93
                "fedadmin-only" => _("Only federation admins"),
94
                "all" => _("All institutions"),
95
            ];
96
        }
97
        $listTail = "";
98
        foreach ($this->enumPrettyPrints as $optionName => $optionDisplay) {
99
            $listTail .= "<option value='$optionName'>$optionDisplay</option>";
100
        }
101
102
        $this->htmlDatatypeTexts = [
103
            \core\Options::TYPECODE_FILE => ["html" => "input type='file'", "tail" => ' size=\'10\''],
104
            \core\Options::TYPECODE_INTEGER => ["html" => "input type='number'", "tail" => ''],
105
            \core\Options::TYPECODE_STRING => ["html" => "input type='string'", "tail" => ''],
106
            \core\Options::TYPECODE_ENUM_LIST => ["html" => "select", "tail" => ">$listTail</select"],
107
            \core\Options::TYPECODE_TEXT => ["html" => "textarea cols='30' rows='3'", "tail" => '></textarea'],
108
        ];
109
        
110
        if ($wizardStyle) {
111
            $this->htmlDatatypeTexts[\core\Options::TYPECODE_BOOLEAN] = ["html" => "input type='checkbox'", "tail" => ''];
112
        } else {
113
            $this->htmlDatatypeTexts[\core\Options::TYPECODE_BOOLEAN] = ["html" => "input type='checkbox' checked", "tail" => ''];            
114
        }
115
    }
116
117
    /**
118
     * creates a table with all the set options prefilled. Only displays options
119
     * of the category indicated.
120
     * @param string $attributePrefix category of option to display
121
     * @param string $fed             the federation we are in
122
     * @return string HTML code <table>
123
     */
124
    public function prefilledOptionTable(string $attributePrefix, $fed)
125
    {
126
        $retval = "<table id='expandable_$attributePrefix" . "_options'>";
127
128
        $prepopulate = [];
129
        foreach ($this->listOfOptions as $existingAttribute) {
130
            if ($existingAttribute['level'] == $this->level) {
131
                $prepopulate[] = $existingAttribute;
132
            }
133
        }
134
        if (is_array($prepopulate) && ( count($prepopulate) > 0 || $attributePrefix == "device-specific" || $attributePrefix == "eap-specific" )) { // editing... fill with values
135
            $retval .= $this->addOptionEdit($attributePrefix, $prepopulate);
136
        } else {
137
            $retval .= $this->addOptionNew($attributePrefix, $fed);
138
        }
139
        $retval .= "</table>";
140
        return $retval;
141
    }
142
143
    /**
144
     * Displays options for a given option class, in Edit mode.
145
     * 
146
     * @param string $class       the class of options that is to be displayed
147
     * @param array  $prepopulate should an empty set of fillable options be displayed, or do we have existing data to prefill with
148
     * @return string
149
     */
150
    private function addOptionEdit(string $class, array $prepopulate = [])
151
    { // no GET class ? we've been called directly:
152
        // this can mean either a new object (list all options with empty values)
153
        // or that an object is to be edited. In that case, $prepopulated has to
154
        // contain the array of existing variables
155
        // we expect the variable $class to contain the class of options
156
        \core\common\Logging::debug_s(4, $class, "CLASS:", "\n");
157
        $retval = "";
158
        $optioninfo = \core\Options::instance();        
159
        $blackListOnPrefill = "user:fedadmin|managedsp:vlan|managedsp:operatorname|managedsp:guest_vlan|managedsp:name";
160
        $blackListOnPrefill .= "|fed:silverbullet";
161
        foreach ($prepopulate as $option) {
162
            if (preg_match("/^$class:/", $option['name']) && !preg_match("/($blackListOnPrefill)/", $option['name'])) {
163
                $optiontypearray = $optioninfo->optionType($option['name']);
164
                \core\common\Logging::debug_s(5, "About to execute optiontext with PREFILL!\n");
165
                $retval .= $this->optiontext([$option['name']], ($optiontypearray["type"] == "file" ? 'ROWID-' . $option['level'] . '-' . $option['row_id'] : $option['value']), $option['lang']);
166
            }
167
        }
168
        return $retval;
169
    }
170
    
171
    /**
172
     * Find which options to expose to UI and which to hide.
173
     * Not all options defined in the database are (always) displayed. Some have
174
     * custom UI not matching the usual dropdown display, some depend on context
175
     * (e.g. OpenRoaming or not, depending on whether the fed operator wants it
176
     * 
177
     * @param string $class the type of options requested
178
     * @param string $fed   the federation TLD, to determine fed ops preference context
179
     * @param string $device - only used with device-specific class - limit options to the given device type
180
     * @return array the list of options to display
181
     */
182
    public static function enumerateOptionsToDisplay($class, $fed, $device='')
183
    {
184
        $optioninfo = \core\Options::instance();
185
        $list = $optioninfo->availableOptions($class);
186
        // use federation context to delete more options, if the feds don't like
187
        // a particular one
188
        $fedInstance = new \core\Federation($fed);
189
        switch ($class) {
190
            case "general":
191
                unset($list[array_search("general:geo_coordinates", $list)]);
192
                break;
193
            case "user":
194
                unset($list[array_search("user:fedadmin", $list)]);
195
                break;
196
            case "managedsp":
197
                unset($list[array_search("managedsp:vlan", $list)]);
198
                unset($list[array_search("managedsp:guest_vlan", $list)]);
199
                unset($list[array_search("managedsp:operatorname", $list)]);
200
                unset($list[array_search("managedsp:name", $list)]);
201
                break;
202
            case "fed":
203
                //normally, we have nothing to hide on that level
204
                // if we are a Managed IdP exclusive deployment, do not display or allow
205
                // to change the "Enable Managed IdP" boolean - it is simply always there
206
                if (\core\CAT::hostedServicesEnabled() && !\core\CAT::radiusProfilesEnabled()) {
207
                    unset($list[array_search("fed:silverbullet", $list)]);
208
                }
209
                if (!\core\CAT::hostedIDPEnabled()) {
210
                    unset($list[array_search("fed:silverbullet-maxusers", $list)]);
211
                    unset($list[array_search("fed:silverbullet-noterm", $list)]);
212
                }
213
                break;
214
            case "media":
215
                if ($fedInstance->getAttributes("fed:openroaming") == []) {
216
                    // no openroaming here
217
                    unset($list[array_search("media:openroaming", $list)]);
218
                }
219
                break;
220
            case "device-specific":
221
                if ($device != '') {
222
                    $factory = new \core\DeviceFactory($device);
223
                    $dev = $factory->device;
224
                    foreach ($list as $l) {
225
                        $optFlag = $optioninfo->optionType($l)['flag'];
226
                        if ($optFlag == "SPECIFIC") {
227
                            $opt = str_replace('device-specific:', '', $l);
228
                            if (!isset($dev->options['device_options']) || !in_array($opt, $dev->options['device_options'])) {
229
                                 \core\common\Logging::debug_s(5, $l, "removing option: ", "\n");
230
                                unset($list[array_search($l, $list)]);
231
                            }
232
                        }
233
                    }
234
                }
235
                 break;
236
            default:
237
                break;
238
        }
239
240
        return $list;
241
    }
242
243
    /**
244
     * Displays options for a given option class, in New mode.
245
     * 
246
     * @param string $class           the class of options that is to be displayed
247
     * @param string $fed             the federation we are in
248
     * @return string
249
     */
250
    private function addOptionNew(string $class, $fed)
251
    {
252
        $retval = "";
253
        $list2 = array_values(OptionDisplay::enumerateOptionsToDisplay($class, $fed));
254
255
        // add as many options as there are different option types
256
        $numberOfOptions = count($list2);
257
        for ($this->optionIterator = 0; $this->optionIterator < $numberOfOptions; $this->optionIterator++) {
258
            $retval .= $this->optiontext($list2);
259
        }
260
        return $retval;
261
    }
262
263
    /**
264
     * produce code for a option-specific tooltip
265
     * @param int     $rowid     the number (once during page build) of the option 
266
     *                           that should get the tooltip
267
     * @param string  $input     the option name. Tooltip for it will be displayed
268
     *                           if we have one available.
269
     * @param boolean $isVisible should the tooltip be visible with the option,
270
     *                           or are they both currently hidden?
271
     * @return string
272
     */
273
    private function tooltip($rowid, $input, $isVisible)
274
    {
275
        \core\common\Entity::intoThePotatoes();
276
        $descriptions = [];
277
        if (count(\config\ConfAssistant::CONSORTIUM['ssid']) > 0) {
278
            $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']);
279
        }
280
        $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 thoroughly 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");
281
        $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);
282
        $descriptions["media:openroaming"] = sprintf(_("By opting in to OpenRoaming, you agree to be bound by the %s."), "eduroam Ecosystem Broker OpenRoaming Identity Provider Policy") .
283
                " " .
284
                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']) .
285
                " " .
286
                _("You are also aware that for best technical interoperability, you need to add a DNS entry into the DNS zone of your RADIUS realm.") .
287
                " " .
288
                _("Read the instructions in the wiki.");
289
        \core\common\Entity::outOfThePotatoes();
290
        if (!isset($descriptions[$input])) {
291
            return "";
292
        }
293
        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>";
294
    }
295
296
    /**
297
     * 
298
     * @param int   $rowid the number (once during page build) of the option 
299
     *                     that should get the tooltip
300
     * @param array $list  elements of the drop-down list
301
     * @return array HTML code and which option is active
302
     * @throws \Exception
303
     */
304
    private function selectElement($rowid, $list)
305
    {
306
        $jsmagic = "onchange='
307
                               if (/#ML#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) {
308
                                   document.getElementById(\"S$rowid-input-langselect\").style.display = \"block\";
309
                                   } else {
310
                                   document.getElementById(\"S$rowid-input-langselect\").style.display = \"none\";
311
                                   }";
312
        foreach (array_keys($this->htmlDatatypeTexts) as $key) {
313
            $jsmagic .= "if (/#" . $key . "#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) {
314
                                  document.getElementById(\"S$rowid-input-file\").style.display = \"" . ($key == \core\Options::TYPECODE_FILE ? "block" : "none") . "\";
315
                                  document.getElementById(\"S$rowid-input-text\").style.display = \"" . ($key == \core\Options::TYPECODE_TEXT ? "block" : "none") . "\";
316
                                  document.getElementById(\"S$rowid-input-string\").style.display = \"" . ($key == \core\Options::TYPECODE_STRING ? "block" : "none") . "\";
317
                                  document.getElementById(\"S$rowid-input-enum_openroaming\").style.display = \"" . ($key == \core\Options::TYPECODE_ENUM_LIST ? "block" : "none") . "\";
318
                                  document.getElementById(\"S$rowid-input-boolean\").style.display = \"" . ($key == \core\Options::TYPECODE_BOOLEAN ? "block" : "none") . "\";
319
                                  document.getElementById(\"S$rowid-input-integer\").style.display = \"" . ($key == \core\Options::TYPECODE_INTEGER ? "block" : "none") . "\";
320
                             }
321
                             ";
322
            // hide all tooltips (each is a <span>, and there are no other <span>s)
323
            $jsmagic .= <<< FOO
324
                    var ourtooltips = document.querySelectorAll(&#34;[id^=&#39;S$rowid-tooltip-&#39;]&#34;);
325
                    for (var i=0; i<ourtooltips.length; i++) {
326
                      ourtooltips[i].style.display = "none";
327
                    }
328
                    var optionnamefull = document.getElementById("option-S$rowid-select").value;
329
                    var firstdelimiter = optionnamefull.indexOf("#");
330
                    var optionname = optionnamefull.substring(0,firstdelimiter);
331
                    var tooltipifany = document.getElementById("S$rowid-tooltip-"+optionname);
332
                    if (tooltipifany != null) {
333
                      tooltipifany.style.display = "block";
334
                    }
335
FOO;
336
        }
337
        $jsmagic .= "'";
338
339
        $optioninfo = \core\Options::instance();
340
        $retval = "<span style='display:flex';>";
341
        $iterator = 0;
342
        $tooltips = "";
343
        $uiElements = new UIElements();
344
        $activelisttype = [];
345
        switch (count($list)) {
346
            case 1: // if there is only one option available, don't introduce an artificial drop-down for it
347
                $value = array_shift($list);
348
                $listtype = $optioninfo->optionType($value);
349
                $retval .= $uiElements->displayName($value);
350
                $retval .= "<input type='hidden' name='option[S$rowid]' value='$value#" . $listtype["type"] . "#" . $listtype["flag"] . "#'/>";
351
                $activelisttype = $listtype;
352
                $tooltips = $this->tooltip($rowid, $value, TRUE);
353
                break;
354
            default:
355
                $retval .= "<select id='option-S$rowid-select' name='option[S$rowid]' $jsmagic>";
356
                $sortArray = [];
357
                foreach ($list as $value) {
358
                    $sortArray[] = $uiElements->displayName($value);
359
                }
360
                array_multisort($sortArray, SORT_ASC, $list);
0 ignored issues
show
Bug introduced by
web\lib\admin\SORT_ASC cannot be passed to array_multisort() as the parameter $rest expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

360
                array_multisort($sortArray, /** @scrutinizer ignore-type */ SORT_ASC, $list);
Loading history...
361
                foreach ($list as $value) {
362
                    $listtype = $optioninfo->optionType($value);
363
                    $retval .= "<option id='option-S$rowid-v-$value' value='$value#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ";
364
                    if ($iterator == $this->optionIterator) {
365
                        $retval .= "selected='selected'";
366
                        $activelisttype = $listtype;
367
                        $tooltips .= $this->tooltip($rowid, $value, TRUE);
368
                    } else {
369
                        $tooltips .= $this->tooltip($rowid, $value, FALSE);
370
                    }
371
                    $retval .= ">" . $uiElements->displayName($value) . "</option>";
372
                    $iterator++;
373
                }
374
375
                if (count($activelisttype) == 0) {
376
                    throw new \Exception("We should have found the active list type by now!");
377
                }
378
                $retval .= "</select>";
379
        }
380
        $retval .= $tooltips;
381
        $retval .= "</span>";
382
383
        return ["TEXT" => $retval, "ACTIVE" => $activelisttype];
384
    }
385
386
    /**
387
     * HTML code to display the language selector
388
     * 
389
     * @param int     $rowid       the number (once during page build) of the option 
390
     *                             that should get the tooltip
391
     * @param boolean $makeVisible is the language selector to be made visible?
392
     * @return string
393
     */
394
    private function selectLanguage($rowid, $makeVisible)
395
    {
396
        \core\common\Entity::intoThePotatoes();
397
        $retval = "<select style='display:" . ($makeVisible ? "block" : "none") . "' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect'>
398
            <option value='' name='select_language' selected>" . _("select language") . "</option>
399
            <option value='C' name='all_languages'>" . _("default/other languages") . "</option>";
400
        foreach (\config\Master::LANGUAGES as $langindex => $possibleLang) {
401
            $thislang = $possibleLang['display'];
402
            $retval .= "<option value='$langindex' name='$langindex'>$thislang</option>";
403
        }
404
        $retval .= "</select>";
405
        \core\common\Entity::outOfThePotatoes();
406
        return $retval;
407
    }
408
409
    /**
410
     * HTML code for a given option. Marks the matching datatype as visible, all other datatypes hidden
411
     * @param int   $rowid      the number (once during page build) of the option 
412
     *                          that should get the tooltip
413
     * @param array $activetype the active datatype that is to be visible
414
     * @return string
415
     */
416
    private function inputFields($rowid, $activetype)
417
    {
418
        $retval = "";
419
        foreach ($this->htmlDatatypeTexts as $key => $type) {
420
            $retval .= "<" . $type['html'] . " style='display:" . ($activetype['type'] == $key ? "block" : "none") . "' name='value[S$rowid-$key]' id='S" . $rowid . "-input-" . $key . "'" . $type['tail'] . ">";
421
        }
422
        return $retval;
423
    }
424
425
    /**
426
     * HTML code to display a "fresh" option (including type selector and JavaScript to show/hide relevant input fields)
427
     * @param int   $rowid the HTML field base name of the option to be displayed
428
     * @param array $list  the list of option names to include in the type selector
429
     * @return string HTML code
430
     * @throws Exception
431
     */
432
    private function noPrefillText(int $rowid, array $list)
433
    {
434
        // first column: the <select> element with the names of options and their field-toggling JS magic
435
        $selectorInfo = $this->selectElement($rowid, $list);
436
        $retval = "<td>" . $selectorInfo["TEXT"] . "</td>";
437
        // second column: the <select> element for language selection - only visible if the active option is multi-lang
438
        $retval .= "<td>" . $this->selectLanguage($rowid, $selectorInfo['ACTIVE']['flag'] == "ML") . "</td>";
439
        // third column: the actual input fields; the data type of the active option is visible, all others hidden
440
        $retval .= "<td>" . $this->inputFields($rowid, $selectorInfo['ACTIVE']) . "</td>";
441
        return $retval;
442
    }
443
444
    /**
445
     * generates HTML code that displays an already set option.
446
     * 
447
     * @param int    $rowid       the HTML field base name of the option to be displayed
448
     * @param string $optionName  the name of the option to display
449
     * @param string $optionValue the value of the option to display
450
     * @param mixed  $optionLang  the language of the option to display
451
     * @return string HTML code
452
     * @throws Exception
453
     */
454
    private function prefillText(int $rowid, string $optionName, string $optionValue, $optionLang)
455
    {
456
        \core\common\Entity::intoThePotatoes();
457
        $retval = "";
458
        $optioninfo = \core\Options::instance();
459
        $loggerInstance = new \core\common\Logging();
460
        $loggerInstance->debug(5, "Executed with PREFILL $optionValue!\n");
461
        $retval .= "<td>";
462
        $uiElements = new UIElements();
463
        $listtype = $optioninfo->optionType($optionName);
464
        $retval .= "<span style='display:flex;'>" . $uiElements->displayName($optionName);
465
        $retval .= $this->tooltip($rowid, $optionName, TRUE) . "</span>";
466
        $retval .= "<input type='hidden' id='option-S$rowid-select' name='option[S$rowid]' value='$optionName#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ></td>";
467
468
        // language tag if any
469
        $retval .= "<td>";
470
        if ($listtype["flag"] == "ML") {
471
472
            $language = "(" . strtoupper($optionLang) . ")";
473
            if ($optionLang == 'C') {
474
                $language = _("(default/other languages)");
475
            }
476
            $retval .= $language;
477
            $retval .= "<input type='hidden' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect' value='" . $optionLang . "' style='display:block'>";
478
        }
479
        $retval .= "</td>";
480
// attribute content
481
        $retval .= "<td>";
482
        $displayedVariant = "";
483
        switch ($listtype["type"]) {
484
            case \core\Options::TYPECODE_COORDINATES:
485
                $this->allLocationCount = $this->allLocationCount + 1;
486
                // display of the locations varies by map provider
487
                $classname = "\web\lib\admin\Map" . \config\ConfAssistant::MAPPROVIDER['PROVIDER'];
488
                $link = $classname::optionListDisplayCode($optionValue, $this->allLocationCount);
489
                $retval .= "<input readonly style='display:none' type='text' name='value[S$rowid-" . \core\Options::TYPECODE_TEXT . "]' id='S$rowid-input-text' value='$optionValue'>$link";
490
                break;
491
            case \core\Options::TYPECODE_FILE:
492
                $retval .= "<input readonly type='text' name='value[S$rowid-" . \core\Options::TYPECODE_STRING . "]' id='S" . $rowid . "-input-string' style='display:none' value='" . urlencode($optionValue) . "'>";
493
                $uiElements = new UIElements();
494
                switch ($optionName) {
495
                    case "eap:ca_file":
496
                    // fall-through intentional: display both types the same way
497
                    case "fed:minted_ca_file":
498
                        $retval .= $uiElements->previewCAinHTML($optionValue);
499
                        break;
500
                    case "general:logo_file":
501
                    // fall-through intentional: display both types the same way
502
                    case "fed:logo_file":
503
                        $retval .= $uiElements->previewImageinHTML($optionValue);
504
                        break;
505
                    case "support:info_file":
506
                        $retval .= $uiElements->previewInfoFileinHTML($optionValue);
507
                        break;
508
                    default:
509
                        $retval .= _("file content");
510
                }
511
                break;
512
            case \core\Options::TYPECODE_ENUM_LIST: // is a string after all
513
                $displayedVariant = $this->enumPrettyPrints[$optionValue];
514
                $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'>";
515
                break;
516
            case \core\Options::TYPECODE_STRING:
517
            // fall-thorugh is intentional; mostly identical HTML code for the three types
518
            case \core\Options::TYPECODE_INTEGER:
519
            // fall-thorugh is intentional; mostly identical HTML code for the three types
520
            case \core\Options::TYPECODE_TEXT:
521
                $displayedVariant = $optionValue; // for all three types, value tag and actual display are identical
522
                $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'>";
523
                break;
524
            case \core\Options::TYPECODE_BOOLEAN:
525
                $displayedVariant = ($optionValue == "on" ? _("on") : _("off"));
526
                $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'>";
527
                break;
528
            default:
529
                // this should never happen!
530
                throw new Exception("Internal Error: unknown attribute type $listtype!");
531
        }
532
        $retval .= "</td>";
533
        \core\common\Entity::outOfThePotatoes();
534
        return $retval;
535
    }
536
537
    /**
538
     * Displays a container for options. Either with prefilled data or empty; if
539
     * empty then has HTML <input> tags with clever javaScript to allow selection
540
     * of different option names and types
541
     * @param array  $list         options which should be displayed; can be only exactly one if existing option, or multiple if new option type
542
     * @param string $prefillValue for an existing option, it's value to be displayed
543
     * @param string $prefillLang  for an existing option, the language of the value to be displayed
544
     * @return string HTML code <tr>
545
     * @throws Exception
546
     */
547
    public function optiontext(array $list, string $prefillValue = NULL, string $prefillLang = NULL)
548
    {
549
        $rowid = mt_rand();
550
551
        $retval = "<tr id='option-S$rowid' style='vertical-align:top'>";
552
553
        $item = "MULTIPLE";
554
        if ($prefillValue === NULL) {
555
            $retval .= $this->noPrefillText($rowid, $list);
556
        }
557
558
        if ($prefillValue !== NULL) {
559
            // prefill is always only called with a list with exactly one element.
560
            // if we see anything else here, get excited.
561
            if (count($list) != 1) {
562
                throw new Exception("Optiontext prefilled display only can work with exactly one option!");
563
            }
564
            $item = array_pop($list);
565
            $retval .= $this->prefillText($rowid, $item, $prefillValue, $prefillLang);
566
        }
567
        $retval .= "
568
569
       <td>
570
          <button type='button' class='delete' onclick='";
571
        if ($prefillValue !== NULL && $item == "general:geo_coordinates") {
572
            $funcname = "Map" . \config\ConfAssistant::MAPPROVIDER['PROVIDER'] . 'DeleteCoord';
573
            $retval .= 'if (typeof ' . $funcname . ' === "function") { ' . $funcname . '(' . $this->allLocationCount . '); } ';
574
        }
575
        $retval .= 'deleteOption("option-S' . $rowid . '")';
576
        $retval .= "'>-</button>
577
       </td>
578
    </tr>";
579
        return $retval;
580
    }
581
}
582