Passed
Push — master ( ee35e3...cc2678 )
by Andreas
23:32
created

midcom_helper_toolbar::add_help_item()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0582

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 15
c 1
b 0
f 0
nc 8
nop 5
dl 0
loc 24
ccs 11
cts 13
cp 0.8462
crap 4.0582
rs 9.7666
1
<?php
2
/**
3
 * @package midcom.helper
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * This class is a generic toolbar class. It supports enabling
11
 * and disabling of buttons, icons and hover-helptexts (currently
12
 * rendered using TITLE tags).
13
 *
14
 * A single button in the toolbar is represented using an associative
15
 * array with the following elements:
16
 *
17
 * <code>
18
 * $item = [
19
 *     MIDCOM_TOOLBAR_URL => $url,
20
 *     MIDCOM_TOOLBAR_LABEL => $label,
21
 *     MIDCOM_TOOLBAR_HELPTEXT => $helptext,
22
 *     MIDCOM_TOOLBAR_ICON => $icon,
23
 *     MIDCOM_TOOLBAR_ENABLED => $enabled,
24
 *     MIDCOM_TOOLBAR_HIDDEN => $hidden
25
 *     MIDCOM_TOOLBAR_OPTIONS => array $options,
26
 *     MIDCOM_TOOLBAR_SUBMENU => midcom_helper_toolbar $submenu,
27
 *     MIDCOM_TOOLBAR_ACCESSKEY => (char) 'a',
28
 *     MIDCOM_TOOLBAR_POST => true,
29
 *     MIDCOM_TOOLBAR_POST_HIDDENARGS => array $args,
30
 * ];
31
 * </code>
32
 *
33
 * The URL parameter can be interpreted in three different ways:
34
 * If it is a relative URL (not starting with 'http[s]://' or at least
35
 * a '/') it will be interpreted relative to the current Anchor
36
 * Prefix as defined in the active MidCOM context. Otherwise, the URL
37
 * is used as-is. Note, that the Anchor-Prefix is appended immediately
38
 * when the item is added, not when the toolbar is rendered.
39
 *
40
 * The original URL (before prepending anything) is stored internally;
41
 * so in all places where you reference an element by-URL, you can use
42
 * the original URL if you wish (actually, both URLs are recognized
43
 * during the translation into an id).
44
 *
45
 * The label is the text shown as the button, the helptext is used as
46
 * TITLE value to the anchor, and will be shown when hovering over the
47
 * link therefore. Set it to null, to suppress this feature (this is the
48
 * default).
49
 *
50
 * The icon is a relative URL within the static MidCOM tree, for example
51
 * 'stock-icons/16x16/attach.png'. Set it to null, to suppress the display
52
 * of an icon (this is the default)
53
 *
54
 * By default, as shown below, the toolbar system renders a standard Hyperlink.
55
 * If you set MIDCOM_TOOLBAR_POST to true however, a form is used instead.
56
 * This is important if you want to provide operations directly behind the
57
 * toolbar entries - you'd run into problems with HTTP Link Prefetching
58
 * otherwise. It is also useful if you want to pass complex operations
59
 * to the URL target, as the option MIDCOM_TOOLBAR_POST_HIDDENARGS allows
60
 * you to add HIDDEN variables to the form. These arguments will be automatically
61
 * run through htmlspecialchars when rendering. By default, standard links will
62
 * be rendered, POST versions will only be used if explicitly requested.
63
 *
64
 * Note, that while this should prevent link prefetching on the POST entries,
65
 * this is a big should. Due to its lack of standardization, it is strongly
66
 * recommended to check for a POST request when processing such toolbar
67
 * targets, using something like this:
68
 *
69
 * <code>
70
 * if ($_SERVER['REQUEST_METHOD'] != 'post')
71
 * {
72
 *     throw new midcom_error_forbidden('Only POST requests are allowed here.');
73
 * }
74
 * </code>
75
 *
76
 * The enabled boolean flag is set to true (the default) if the link should
77
 * be clickable, or to false otherwise.
78
 *
79
 * The hidden boolean flag is very similar to the enabled one: Instead of
80
 * having unclickable links, it just hides the toolbar button entirely.
81
 * This is useful for access control checks, where you want to completely
82
 * hide items without access. The difference from just not adding the
83
 * corresponding variable is that you can have a consistent set of
84
 * toolbar options in a "template" which you just need to tweak by
85
 * setting this flag. (Note, that there is no explicit access
86
 * control checks in the toolbar helper itself, as this would mean that
87
 * the corresponding content objects need to be passed into the toolbar,
88
 * which is not feasible with the large number of toolbars in use in NAP
89
 * for example.)
90
 *
91
 * The midcom_toolbar_submenu can be used to create nested submenus by adding a pointer
92
 * to a new toolbar object.
93
 *
94
 * The toolbar gets rendered as an unordered list, letting you define the
95
 * CSS id and/or class tags of the list itself. The default class for
96
 * example used the well-known horizontal-UL approach to transform this
97
 * into a real toolbar. The output of the draw call therefore looks like
98
 * this:
99
 *
100
 * The <b>accesskey</b> option is used to assign an accesskey to the toolbar item.
101
 * It will be rendered in the toolbar text as either underlining the key or stated in
102
 * parentheses behind the text.
103
 *
104
 * <pre>
105
 * &lt;ul [class="$class"] [id="$id"]&gt;
106
 *   &lt;li class="(enabled|disabled)"&gt;
107
 *     [&lt;a href="$url" [title="$helptext"] [ $options as $key =&gt; $val ]&gt;]
108
 *       [&lt;img src="$calculated_image_url"&gt;]
109
 *       $label
110
 *      [new submenu here]
111
 *     [&lt;/a&gt;]
112
 *   &lt;/li&gt;
113
 * &lt;/ul&gt;
114
 * </pre>
115
 *
116
 * Both class and id can be null, indicating no style should be selected.
117
 * By default, the class will use "midcom_toolbar" and no id style, which
118
 * will yield a traditional MidCOM toolbar. Of course, the
119
 * style sheet must be loaded to support this. Note, that this style assumes
120
 * 16x16 height icons in its toolbar rendering. Larger or smaller icons
121
 * will look ugly in the layout.
122
 *
123
 * The options array. You can use the options array to make simple changes to the toolbar items.
124
 * Here's a quick example to remove the underlining.
125
 * <code>
126
 * foreach ($toolbar->items as $index => $item) {
127
 *     $toolbar->items[$index][MIDCOM_TOOLBAR_OPTIONS] = [ "style" => "text-decoration:none;"];
128
 * }
129
 * </code>
130
 * This will add style="text-decoration:none;" to all the links in the toolbar.
131
 *
132
 * @package midcom.helper
133
 */
134
class midcom_helper_toolbar
135
{
136
    /**
137
     * The CSS ID-Style rule that should be used for the toolbar.
138
     * Set to null if none should be used.
139
     *
140
     * @var string
141
     */
142
    public $id_style;
143
144
    /**
145
     * The CSS class-Style rule that should be used for the toolbar.
146
     * Set to null if none should be used.
147
     *
148
     * @var string
149
     */
150
    public $class_style;
151
152
    /**
153
     * The toolbar's label
154
     *
155
     * @var string
156
     */
157
    protected $label = '';
158
159
    /**
160
     * The items in the toolbar.
161
     *
162
     * The array consists of Arrays outlined in the class introduction.
163
     * You can modify existing items in this collection but you should use
164
     * the class methods to add or delete existing items. Also note that
165
     * relative URLs are processed upon the invocation of add_item(), if
166
     * you change URL manually, you have to ensure a valid URL by yourself
167
     * or use update_item_url, which is recommended.
168
     *
169
     * @var Array
170
     */
171
    public $items = [];
172
173
    /**
174
     * Allow our users to add arbitrary data to the toolbar.
175
     *
176
     * This is for example used to track which items have been added to a toolbar
177
     * when it is possible that the adders are called repeatedly.
178
     *
179
     * The entries should be namespaced according to the usual MidCOM
180
     * Namespacing rules.
181
     *
182
     * @var Array
183
     */
184
    public $customdata = [];
185
186
    private $rendered = false;
187
188
    /**
189
     * Basic constructor, initializes the class and sets defaults for the
190
     * CSS style if omitted.
191
     *
192
     * Note that the styles can be changed after construction by updating
193
     * the id_style and class_style members.
194
     */
195 341
    public function __construct(string $class_style = 'midcom_toolbar', string $id_style = null)
196
    {
197 341
        $this->id_style = $id_style;
198 341
        $this->class_style = $class_style;
199 341
    }
200
201 5
    public function is_rendered() : bool
202
    {
203 5
        return $this->rendered;
204
    }
205
206 5
    public function get_label() : string
207
    {
208 5
        return $this->label;
209
    }
210
211
    /**
212
     *
213
     * @param string $label
214
     */
215 52
    public function set_label(string $label)
216
    {
217 52
        $this->label = $label;
218 52
    }
219
220
    /**
221
     * Add a help item to the toolbar.
222
     */
223 2
    public function add_help_item(string $help_id, string $component = null, string $label = null, string $anchor = null, $before = -1)
224
    {
225 2
        $uri = "__ais/help/";
226 2
        if ($component !== null) {
227
            $uri .= $component . '/';
228
        }
229 2
        $uri .= $help_id . '/';
230
231 2
        if ($anchor !== null) {
232
            $uri .= "#{$anchor}";
233
        }
234
235 2
        if ($label === null) {
236 2
            $label = midcom::get()->i18n->get_string('help', 'midcom.admin.help');
237
        }
238
239 2
        $this->add_item([
240 2
            MIDCOM_TOOLBAR_URL => $uri,
241 2
            MIDCOM_TOOLBAR_LABEL => $label,
242 2
            MIDCOM_TOOLBAR_GLYPHICON => 'question',
243
            MIDCOM_TOOLBAR_OPTIONS => [
244
                'target' => '_blank',
245
            ]],
246
            $before
247
        );
248 2
    }
249
250
    /**
251
     * Add an item to the toolbar.
252
     *
253
     * Set before to the index of the element before which you want to insert
254
     * the item or use -1 if you want to append an item. Alternatively,
255
     * instead of specifying an index, you can specify a URL instead.
256
     *
257
     * This member will process the URL and append the anchor prefix in case
258
     * the URL is a relative one.
259
     *
260
     * Invalid positions will result in a MidCOM Error.
261
     *
262
     * @param mixed $before The index before which the item should be inserted.
263
     *     Use -1 for appending at the end, use a string to insert
264
     *     it before a URL, an integer will insert it before a
265
     *     given index.
266
     * @see midcom_helper_toolbar::get_index_from_url()
267
     * @see midcom_helper_toolbar::_check_index()
268
     * @see midcom_helper_toolbar::clean_item()
269
     */
270 184
    public function add_item(array $item, $before = -1)
271
    {
272 184
        if ($before != -1) {
273
            $before = $this->_check_index($before, false);
274
        }
275 184
        $item = $this->clean_item($item);
276
277 184
        if ($before == -1) {
278 184
            $this->items[] = $item;
279
        } elseif ($before == 0) {
280
            array_unshift($this->items, $item);
281
        } else {
282
            $start = array_slice($this->items, 0, $before - 1);
283
            $start[] = $item;
284
            $this->items = array_merge($start, array_slice($this->items, $before));
285
        }
286 184
    }
287
288
    /**
289
     * Convenience shortcut to add multiple buttons at the same item
290
     *
291
     * @param array $items The items to add.
292
     * @param mixed $before The index before which the item should be inserted.
293
     *     Use -1 for appending at the end, use a string to insert
294
     *     it before a URL, an integer will insert it before a
295
     *     given index.
296
     */
297 126
    public function add_items(array $items, $before = -1)
298
    {
299 126
        foreach ($items as $item) {
300 121
            $this->add_item($item, $before);
301
        }
302 126
    }
303
304
    /**
305
     * Add an item to another item by either adding the item to the MIDCOM_TOOLBAR_SUBMENU
306
     * or creating a new subtoolbar and adding the item there.
307
     */
308
    public function add_item_to_index(array $item, int $index) : bool
309
    {
310
        $item = $this->clean_item($item);
311
        if (!array_key_exists($index, $this->items)) {
312
            debug_add("Insert of item {$item[MIDCOM_TOOLBAR_LABEL]} into index $index failed");
313
            return false;
314
        }
315
316
        if (empty($this->items[$index][MIDCOM_TOOLBAR_SUBMENU])) {
317
            $this->items[$index][MIDCOM_TOOLBAR_SUBMENU] = new midcom_helper_toolbar($this->class_style, $this->id_style);
318
        }
319
320
        $this->items[$index][MIDCOM_TOOLBAR_SUBMENU]->items[] = $item;
321
322
        return true;
323
    }
324
325
    /**
326
     * Clean up an item that is added, making sure that the item has all the
327
     * needed options and indexes.
328
     */
329 185
    public function clean_item(array $item) : array
330
    {
331 185
        static $used_access_keys = [];
332
333
        $defaults = [
334 185
            MIDCOM_TOOLBAR_URL => './',
335
            MIDCOM_TOOLBAR_OPTIONS => [],
336
            MIDCOM_TOOLBAR_HIDDEN => false,
337
            MIDCOM_TOOLBAR_HELPTEXT => '',
338
            MIDCOM_TOOLBAR_ICON => null,
339
            MIDCOM_TOOLBAR_GLYPHICON => null,
340
            MIDCOM_TOOLBAR_ENABLED => true,
341
            MIDCOM_TOOLBAR_POST => false,
342
            MIDCOM_TOOLBAR_POST_HIDDENARGS => [],
343
            MIDCOM_TOOLBAR_ACCESSKEY => null
344
        ];
345
346 185
        $item = array_replace($defaults, $item);
347
348 185
        if (   !empty($item[MIDCOM_TOOLBAR_ACCESSKEY])
349 185
            && !array_key_exists($item[MIDCOM_TOOLBAR_ACCESSKEY], $used_access_keys)) {
350
            // We have valid access key, add it to help text
351 10
            $prefix = 'Alt-';
352 10
            if (   isset($_SERVER['HTTP_USER_AGENT'])
353 10
                && strstr($_SERVER['HTTP_USER_AGENT'], 'Macintosh')) {
354
                // Mac users
355
                $prefix = 'Ctrl-Alt-';
356
            }
357 10
            $hotkey = $prefix . strtoupper($item[MIDCOM_TOOLBAR_ACCESSKEY]);
358
359 10
            if ($item[MIDCOM_TOOLBAR_HELPTEXT] == '') {
360 10
                $item[MIDCOM_TOOLBAR_HELPTEXT] = $hotkey;
361
            } else {
362
                $item[MIDCOM_TOOLBAR_HELPTEXT] .= " ({$hotkey})";
363
            }
364 10
            $used_access_keys[$item[MIDCOM_TOOLBAR_ACCESSKEY]] = true;
365
        }
366
367 185
        $this->set_url($item, $item[MIDCOM_TOOLBAR_URL]);
368 185
        return $item;
369
    }
370
371 185
    private function set_url(array &$item, string $url)
372
    {
373 185
        $item[MIDCOM_TOOLBAR__ORIGINAL_URL] = $url;
374 185
        if (   (   empty($item[MIDCOM_TOOLBAR_OPTIONS]["rel"])
375
                // Some items may want to keep their links unmutilated
376 185
                || $item[MIDCOM_TOOLBAR_OPTIONS]["rel"] != "directlink")
377 185
            && !str_starts_with($url, '/')
378 185
            && !preg_match('|^https?://|', $url)) {
379 157
            $url = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $url;
0 ignored issues
show
Bug introduced by
Are you sure midcom_core_context::get...M_CONTEXT_ANCHORPREFIX) of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

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

379
            $url = /** @scrutinizer ignore-type */ midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $url;
Loading history...
380
        }
381 185
        $item[MIDCOM_TOOLBAR_URL] = $url;
382 185
    }
383
384
    /**
385
     * Removes a toolbar item based on its index or its URL
386
     *
387
     * It will trigger a MidCOM Error upon an invalid index.
388
     *
389
     * @param mixed $index The (integer) index or URL to remove.
390
     * @see midcom_helper_toolbar::get_index_from_url()
391
     * @see midcom_helper_toolbar::_check_index()
392
     */
393
    public function remove_item($index)
394
    {
395
        $index = $this->_check_index($index);
396
397
        if ($index == 0) {
398
            array_shift($this->items);
399
        } elseif ($index == count($this->items) -1) {
400
            array_pop($this->items);
401
        } else {
402
            $this->items = array_merge(array_slice($this->items, 0, $index - 1),
403
                array_slice($this->items, $index + 1));
404
        }
405
    }
406
407
    /**
408
     * Clears the complete toolbar.
409
     */
410
    public function remove_all_items()
411
    {
412
        $this->items = [];
413
    }
414
415
    /**
416
     * Moves an item on place upwards in the list.
417
     *
418
     * This will only work, of course, if you are not working with the top element.
419
     *
420
     * @param mixed $index The integer index or URL of the item to move upwards.
421
     */
422
    public function move_item_up($index)
423
    {
424
        if ($index == 0) {
425
            throw new midcom_error('Cannot move the top element upwards.');
426
        }
427
        $index = $this->_check_index($index);
428
429
        $tmp = $this->items[$index];
430
        $this->items[$index] = $this->items[$index - 1];
431
        $this->items[$index - 1] = $tmp;
432
    }
433
434
    /**
435
     * Moves an item on place downwards in the list.
436
     *
437
     * This will only work, of course, if you are not working with the bottom element.
438
     *
439
     * @param mixed $index The integer index or URL of the item to move downwards.
440
     */
441
    public function move_item_down($index)
442
    {
443
        if ($index == (count($this->items) - 1)) {
444
            throw new midcom_error('Cannot move the bottom element downwards.');
445
        }
446
        $index = $this->_check_index($index);
447
448
        $tmp = $this->items[$index];
449
        $this->items[$index] = $this->items[$index + 1];
450
        $this->items[$index + 1] = $tmp;
451
    }
452
453
    /**
454
     * Set's an item's enabled flag to true.
455
     *
456
     * @param mixed $index The integer index or URL of the item to enable.
457
     */
458
    public function enable_item($index)
459
    {
460
        $index = $this->_check_index($index);
461
        $this->items[$index][MIDCOM_TOOLBAR_ENABLED] = true;
462
    }
463
464
    /**
465
     * Set's an item's enabled flag to false.
466
     *
467
     * @param mixed $index The integer index or URL of the item to disable.
468
     */
469 12
    public function disable_item($index)
470
    {
471 12
        $index = $this->_check_index($index, false);
472
473 12
        if ($index !== null) {
474 12
            $this->items[$index][MIDCOM_TOOLBAR_ENABLED] = false;
475
        }
476 12
    }
477
478
    /**
479
     * Set's an item's hidden flag to true.
480
     *
481
     * @param mixed $index The integer index or URL of the item to hide.
482
     */
483 7
    public function hide_item($index)
484
    {
485 7
        $index = $this->_check_index($index, false);
486
487 7
        if ($index !== null) {
488 5
            $this->items[$index][MIDCOM_TOOLBAR_HIDDEN] = true;
489
        }
490 7
    }
491
492
    /**
493
     * Set's an item's hidden flag to false.
494
     *
495
     * @param mixed $index The integer index or URL of the item to show.
496
     */
497
    public function show_item($index)
498
    {
499
        $index = $this->_check_index($index);
500
        $this->items[$index][MIDCOM_TOOLBAR_HIDDEN] = false;
501
    }
502
503
    /**
504
     * Updates an items URL using the same rules as in add_item.
505
     *
506
     * @param mixed $index The integer index or URL of the item to update.
507
     * @see midcom_helper_toolbar::get_index_from_url()
508
     * @see midcom_helper_toolbar::_check_index()
509
     * @see midcom_helper_toolbar::add_item()
510
     */
511
    public function update_item_url($index, string $url)
512
    {
513
        $index = $this->_check_index($index);
514
        $this->set_url($this->items[$index], $url);
515
    }
516
517
    /**
518
     * Renders the toolbar and returns it as a string.
519
     */
520 18
    public function render() : string
521
    {
522
        $visible_items = array_filter($this->items, function ($item) {
523 13
            return !$item[MIDCOM_TOOLBAR_HIDDEN];
524 18
        });
525 18
        $this->rendered = true;
526
527 18
        if (empty($visible_items)) {
528 10
            debug_add('Tried to render an empty toolbar, returning an empty string.');
529 10
            return '';
530
        }
531
532
        // List header
533 13
        $output = '<ul';
534 13
        if ($this->class_style !== null) {
535 13
            $output .= " class='{$this->class_style}'";
536
        }
537 13
        if ($this->id_style !== null) {
538
            $output .= " id='{$this->id_style}'";
539
        }
540 13
        $output .= '>';
541
542 13
        $last = count($visible_items);
543 13
        $first_class = ($last === 1) ? 'only_item' : 'first_item';
544
        // List items
545 13
        foreach ($visible_items as $i => $item) {
546 13
            $output .= '<li class="';
547 13
            if ($i == 0) {
548 13
                $output .= $first_class . ' ';
549 11
            } elseif ($i == $last) {
550
                $output .= 'last_item ';
551
            }
552
553 13
            if ($item[MIDCOM_TOOLBAR_ENABLED]) {
554 13
                $output .= 'enabled">';
555
            } else {
556 9
                $output .= 'disabled">';
557
            }
558
559 13
            if ($item[MIDCOM_TOOLBAR_POST]) {
560
                $output .= $this->_render_post_item($item);
561
            } else {
562 13
                $output .= $this->_render_link_item($item);
563
            }
564
565 13
            $output .= '</li>';
566
        }
567
568
        // List footer
569 13
        $output .= '</ul>';
570
571 13
        return $output;
572
    }
573
574
    /**
575
     * Generate a label for the item that includes its accesskey
576
     */
577 13
    private function _generate_item_label(array $item) : string
578
    {
579 13
        $label = htmlentities($item[MIDCOM_TOOLBAR_LABEL], ENT_COMPAT, "UTF-8");
580
581 13
        if (!empty($item[MIDCOM_TOOLBAR_ACCESSKEY])) {
582
            // Try finding uppercase version of the accesskey first
583 6
            $accesskey = strtoupper($item[MIDCOM_TOOLBAR_ACCESSKEY]);
584 6
            $position = strpos($label, $accesskey);
585 6
            if (   $position === false
586 6
                && midcom::get()->i18n->get_current_language() == 'en') {
587
                // Try lowercase, too
588 5
                $accesskey = strtolower($accesskey);
589 5
                $position = strpos($label, $accesskey);
590
            }
591 6
            if ($position !== false) {
592 6
                $label = substr_replace($label, "<span style=\"text-decoration: underline;\">{$accesskey}</span>", $position, 1);
593
            }
594
        }
595
596 13
        return $label;
597
    }
598
599
    /**
600
     * Render a regular a href... based link target.
601
     */
602 13
    private function _render_link_item(array $item) : string
603
    {
604 13
        $output = '';
605 13
        $attributes = $this->get_item_attributes($item);
606
607 13
        if ($item[MIDCOM_TOOLBAR_ENABLED]) {
608 13
            $tagname = 'a';
609 13
            $attributes['href'] = $item[MIDCOM_TOOLBAR_URL];
610
        } else {
611 9
            $tagname = !empty($attributes['title']) ? 'abbr' : 'span';
612
        }
613
614 13
        $output .= '<' . $tagname;
615 13
        foreach ($attributes as $key => $val) {
616 13
            $output .= ' ' . $key . '="' . htmlspecialchars($val) . '"';
617
        }
618 13
        $output .= '>';
619
620 13
        if ($item[MIDCOM_TOOLBAR_GLYPHICON] !== null) {
621 13
            $class = 'fa fa-' . $item[MIDCOM_TOOLBAR_GLYPHICON];
622 13
            $output .= "<i class='{$class}'></i>";
623
        } elseif ($item[MIDCOM_TOOLBAR_ICON] !== null) {
624
            $url = MIDCOM_STATIC_URL . '/' . $item[MIDCOM_TOOLBAR_ICON];
625
            $output .= "<img src='{$url}' alt=\"{$item[MIDCOM_TOOLBAR_HELPTEXT]}\" />";
626
        }
627
628 13
        $output .= '&nbsp;<span class="toolbar_label">' . $this->_generate_item_label($item) . "</span>";
629 13
        $output .= '</' . $tagname . '>';
630
631 13
        if (!empty($item[MIDCOM_TOOLBAR_SUBMENU])) {
632
            $output .= $item[MIDCOM_TOOLBAR_SUBMENU]->render();
633
        }
634
635 13
        return $output;
636
    }
637
638 13
    private function get_item_attributes(array $item) : array
639
    {
640 13
        $attributes = ($item[MIDCOM_TOOLBAR_ENABLED]) ? $item[MIDCOM_TOOLBAR_OPTIONS] : [];
641
642 13
        if ($item[MIDCOM_TOOLBAR_HELPTEXT] !== null) {
643 13
            $attributes['title'] = $item[MIDCOM_TOOLBAR_HELPTEXT];
644
        }
645
646 13
        if (   $item[MIDCOM_TOOLBAR_ENABLED]
647 13
            && $item[MIDCOM_TOOLBAR_ACCESSKEY] !== null) {
648 6
            $attributes['class'] = 'accesskey';
649 6
            $attributes['accesskey'] = $item[MIDCOM_TOOLBAR_ACCESSKEY];
650
        }
651 13
        return $attributes;
652
    }
653
654
    /**
655
     * Render a form based link target.
656
     */
657
    private function _render_post_item(array $item) : string
658
    {
659
        $output = '';
660
661
        if ($item[MIDCOM_TOOLBAR_ENABLED]) {
662
            $output .= "<form method=\"post\" action=\"{$item[MIDCOM_TOOLBAR_URL]}\">";
663
            $output .= "<div><button type=\"submit\" name=\"midcom_helper_toolbar_submit\"";
664
665
            foreach ($this->get_item_attributes($item) as $key => $val) {
666
                $output .= ' ' . $key . '="' . htmlspecialchars($val) . '"';
667
            }
668
            $output .= '>';
669
        }
670
671
        if ($item[MIDCOM_TOOLBAR_GLYPHICON] !== null) {
672
            $class = 'fa fa-' . $item[MIDCOM_TOOLBAR_GLYPHICON];
673
            $output .= "<i class='{$class}'></i>";
674
        } elseif ($item[MIDCOM_TOOLBAR_ICON]) {
675
            $url = MIDCOM_STATIC_URL . "/{$item[MIDCOM_TOOLBAR_ICON]}";
676
            $output .= "<img src=\"{$url}\" alt=\"{$item[MIDCOM_TOOLBAR_HELPTEXT]}\" />";
677
        }
678
679
        $label = $this->_generate_item_label($item);
680
        $output .= " {$label}";
681
682
        if ($item[MIDCOM_TOOLBAR_ENABLED]) {
683
            $output .= '</button>';
684
            foreach ($item[MIDCOM_TOOLBAR_POST_HIDDENARGS] as $key => $value) {
685
                $key = htmlspecialchars($key);
686
                $value = htmlspecialchars($value);
687
                $output .= "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\"/>";
688
            }
689
            $output .= '</div></form>';
690
        }
691
692
        if (!empty($item[MIDCOM_TOOLBAR_SUBMENU])) {
693
            $output .= $item[MIDCOM_TOOLBAR_SUBMENU]->render();
694
        }
695
696
        return $output;
697
    }
698
699
    /**
700
     * Traverse all available items and return the first
701
     * element whose URL matches the value passed to the function.
702
     *
703
     * Note, that if two items point to the same URL, only the first one
704
     * will be reported.
705
     */
706 19
    public function get_index_from_url(string $url) : ?int
707
    {
708 19
        foreach ($this->items as $i => $item) {
709 17
            if (   $item[MIDCOM_TOOLBAR_URL] == $url
710 17
                || $item[MIDCOM_TOOLBAR__ORIGINAL_URL] == $url) {
711 17
                return $i;
712
            }
713
        }
714 2
        return null;
715
    }
716
717
    /**
718
     * Check an index for validity.
719
     *
720
     * It will automatically convert a string-based URL into an
721
     * Index (if possible); if the URL can't be found, it will
722
     * also trigger an error. The translated URL is returned by the
723
     * function.
724
     *
725
     * @param mixed $index The integer index or URL to check
726
     */
727 19
    protected function _check_index($index, bool $raise_error = true) :?int
728
    {
729 19
        if (is_string($index)) {
730 19
            $url = $index;
731 19
            debug_add("Translating the URL '{$url}' into an index.");
732 19
            $index = $this->get_index_from_url($url);
733 19
            if ($index === null) {
734 2
                debug_add("Invalid URL '{$url}', URL not found.", MIDCOM_LOG_ERROR);
735
736 2
                if ($raise_error) {
737
                    throw new midcom_error("Invalid URL '{$url}', URL not found.");
738
                }
739 2
                return null;
740
            }
741
        }
742 17
        if ($index >= count($this->items)) {
743
            throw new midcom_error("Invalid index {$index}, it is off-the-end.");
744
        }
745 17
        if ($index < 0) {
746
            throw new midcom_error("Invalid index {$index}, it is negative.");
747
        }
748 17
        return $index;
749
    }
750
751
    /**
752
     * Binds this toolbar instance to a DBA content object using the MidCOM toolbar service.
753
     *
754
     * @see midcom_services_toolbars
755
     */
756 52
    public function bind_to(midcom_core_dbaobject $object)
757
    {
758 52
        midcom::get()->toolbars->bind_toolbar_to_object($this, $object);
759 52
    }
760
}
761