1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2017 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