xref: /webtrees/app/Menu.php (revision 13abd6f3a37322f885d85df150e105d27ad81f8d)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2016 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16namespace Fisharebest\Webtrees;
17
18use Rhumsaa\Uuid\Uuid;
19
20/**
21 * System for generating menus.
22 */
23class Menu {
24	/** @var string The text to be displayed in the mneu */
25	private $label;
26
27	/** @var string The target URL or href*/
28	private $link;
29
30	/** @var string The CSS class used to style this menu item */
31	private $class;
32
33	/** @var string[] A list of optional HTML attributes, such as onclick or data-xxx */
34	private $attrs;
35
36	/** @var Menu[] An optional list of sub-menus. */
37	private $submenus;
38
39	/** @var string Used internally to create javascript menus */
40	private $parentmenu;
41
42	/** @var string Used to format javascript menus */
43	private $submenuclass;
44
45	/** @var string Used to format javascript menus */
46	private $menuclass;
47
48	/**
49	 * Constructor for the menu class
50	 *
51	 * @param string   $label    The label for the menu item
52	 * @param string   $link     The target URL
53	 * @param string   $class    A CSS class
54	 * @param string[] $attrs    Optional attributes, such as onclick or data-xxx
55	 * @param Menu[]   $submenus Any submenus
56	 */
57	public function __construct($label, $link = '#', $class = '', array $attrs = [], array $submenus = []) {
58		$this
59			->setLabel($label)
60			->setLink($link)
61			->setClass($class)
62			->setAttrs($attrs)
63			->setSubmenus($submenus);
64	}
65
66	/**
67	 * Convert this menu to an HTML list, for easy rendering of
68	 * lists of menus/nulls.
69	 *
70	 * @return string
71	 */
72	public function __toString() {
73		return $this->getMenuAsList();
74	}
75
76	/**
77	 * Render this menu using Bootstrap markup
78	 *
79	 * @return string
80	 */
81	public function bootstrap() {
82		if ($this->submenus) {
83			$submenus = '';
84			foreach ($this->submenus as $submenu) {
85				$submenus .= $submenu->bootstrap();
86			}
87
88			return
89				'<li class="' . $this->class . ' dropdown">' .
90				'<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">' .
91				$this->label .
92				' <span class="caret"></span></a>' .
93				'<ul class="dropdown-menu" role="menu">' .
94				$submenus .
95				'</ul>' .
96				'</li>';
97		} else {
98			$attrs = '';
99			foreach ($this->attrs as $key => $value) {
100				$attrs .= ' ' . $key . '="' . Filter::escapeHtml($value) . '"';
101			}
102
103			return '<li class="' . $this->class . '"><a href="' . $this->link . '"' . $attrs . '>' . $this->label . '</a></li>';
104		}
105	}
106
107	/**
108	 * Get the optional attributes.
109	 *
110	 * @return string[]
111	 */
112	public function getAttrs() {
113		return $this->attrs;
114	}
115
116	/**
117	 * Set the optional attributes.
118	 *
119	 * @param string[] $attrs
120	 *
121	 * @return $this
122	 */
123	public function setAttrs(array $attrs) {
124		$this->attrs = $attrs;
125
126		return $this;
127	}
128
129	/**
130	 * Set the CSS classes for the (legacy) javascript menus
131	 *
132	 * @param string $menuclass
133	 * @param string $submenuclass
134	 */
135	public function addClass($menuclass, $submenuclass = '') {
136		$this->menuclass    = $menuclass;
137		$this->submenuclass = $submenuclass;
138	}
139
140	/**
141	 * Get the class.
142	 *
143	 * @return string
144	 */
145	public function getClass() {
146		return $this->class;
147	}
148
149	/**
150	 * Set the class.
151	 *
152	 * @param string $class
153	 *
154	 * @return $this
155	 */
156	public function setClass($class) {
157		$this->class = $class;
158
159		return $this;
160	}
161
162	/**
163	 * Get the label.
164	 *
165	 * @return string
166	 */
167	public function getLabel() {
168		return $this->label;
169	}
170
171	/**
172	 * Set the label.
173	 *
174	 * @param string $label
175	 *
176	 * @return $this
177	 */
178	public function setLabel($label) {
179		$this->label = $label;
180
181		return $this;
182	}
183
184	/**
185	 * Get the link.
186	 *
187	 * @return string
188	 */
189	public function getLink() {
190		return $this->link;
191	}
192
193	/**
194	 * Set the link.
195	 *
196	 * @param string $link
197	 *
198	 * @return $this
199	 */
200	public function setLink($link) {
201		$this->link = $link;
202
203		return $this;
204	}
205
206	/**
207	 * Add a submenu to this menu
208	 *
209	 * @param Menu $menu
210	 *
211	 * @return $this
212	 */
213	public function addSubmenu($menu) {
214		$this->submenus[] = $menu;
215
216		return $this;
217	}
218
219	/**
220	 * Render this menu using javascript popups..
221	 *
222	 * @return string
223	 */
224	public function getMenu() {
225		$menu_id     = 'menu-' . Uuid::uuid4();
226		$sub_menu_id = 'sub-' . $menu_id;
227
228		$html = '<a href="' . $this->link . '"';
229		foreach ($this->attrs as $key => $value) {
230			$html .= ' ' . $key . '="' . Filter::escapeHtml($value) . '"';
231		}
232		if (!empty($this->submenus)) {
233			$html .= ' onmouseover="show_submenu(\'' . $sub_menu_id . '\', \'' . $menu_id . '\');"';
234			$html .= ' onmouseout="timeout_submenu(\'' . $sub_menu_id . '\');"';
235		}
236		$html .= '>' . $this->label . '</a>';
237
238		if (!empty($this->submenus)) {
239			$html .= '<div id="' . $sub_menu_id . '" class="' . $this->submenuclass . '"';
240			$html .= ' style="position: absolute; visibility: hidden; z-index: 100; text-align: ' . (I18N::direction() === 'ltr' ? 'left' : 'right') . '"';
241			$html .= ' onmouseover="show_submenu(\'' . $this->parentmenu . '\'); show_submenu(\'' . $sub_menu_id . '\');"';
242			$html .= ' onmouseout="timeout_submenu(\'' . $sub_menu_id . '\');">';
243			foreach ($this->submenus as $submenu) {
244				$submenu->parentmenu = $sub_menu_id;
245				$html .= $submenu->getMenu();
246			}
247			$html .= '</div>';
248		}
249
250		return '<div id="' . $menu_id . '" class="' . $this->menuclass . '">' . $html . '</div>';
251	}
252
253	/**
254	 * Render this menu as an HTML list
255	 *
256	 * @return string
257	 */
258	public function getMenuAsList() {
259		$attrs = '';
260		foreach ($this->attrs as $key => $value) {
261			$attrs .= ' ' . $key . '="' . Filter::escapeHtml($value) . '"';
262		}
263		if ($this->link) {
264			$link = ' href="' . $this->link . '"';
265		} else {
266			$link = '';
267		}
268		$html = '<a' . $link . $attrs . '>' . $this->label . '</a>';
269		if ($this->submenus) {
270			$html .= '<ul>';
271			foreach ($this->submenus as $submenu) {
272				$html .= $submenu->getMenuAsList();
273			}
274			$html .= '</ul>';
275		}
276
277		return '<li class="' . $this->class . '">' . $html . '</li>';
278	}
279
280	/**
281	 * Get the sub-menus.
282	 *
283	 * @return Menu[]
284	 */
285	public function getSubmenus() {
286		return $this->submenus;
287	}
288
289	/**
290	 * Set the sub-menus.
291	 *
292	 * @param Menu[] $submenus
293	 *
294	 * @return $this
295	 */
296	public function setSubmenus(array $submenus) {
297		$this->submenus = $submenus;
298
299		return $this;
300	}
301}
302