flack /
openpsa
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * @package fi.protie.navigation |
||
| 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 | * Versatile class for drawing dynamically navigation elements according to |
||
| 11 | * user preferences. |
||
| 12 | * |
||
| 13 | * <code> |
||
| 14 | * // Initializes the class |
||
| 15 | * $navigation = new fi_protie_navigation(); |
||
| 16 | * |
||
| 17 | * // Display only nodes (folders) |
||
| 18 | * $navigation->list_leaves = false; |
||
| 19 | * |
||
| 20 | * // Expand the whole site tree instead of the active path |
||
| 21 | * $navigation->follow_all = true; |
||
| 22 | * |
||
| 23 | * // Skip 1 level from the beginning of the active path |
||
| 24 | * $navigation->skip_levels = 1; |
||
| 25 | * |
||
| 26 | * // Finally draw the navigation |
||
| 27 | * $navigation->draw(); |
||
| 28 | * </code> |
||
| 29 | * |
||
| 30 | * See the attributes of this class for additional customizing options. |
||
| 31 | * |
||
| 32 | * @package fi.protie.navigation |
||
| 33 | */ |
||
| 34 | class fi_protie_navigation |
||
| 35 | { |
||
| 36 | /** |
||
| 37 | * MidCOM helper class for navigation subsystem. Uses class 'midcom.helper.nav' |
||
| 38 | */ |
||
| 39 | private midcom_helper_nav $_nap; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * Stores the navigation access point history or in other words path to the current point. |
||
| 43 | */ |
||
| 44 | private array $node_path = []; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * ID for the folder to get the navigation |
||
| 48 | */ |
||
| 49 | public ?int $root_id = null; |
||
| 50 | |||
| 51 | /** |
||
| 52 | * Number of the parsed level |
||
| 53 | */ |
||
| 54 | private int $_level = 1; |
||
| 55 | |||
| 56 | /** |
||
| 57 | * The amount of lowest level elements to be skipped. |
||
| 58 | */ |
||
| 59 | public int $skip_levels = 0; |
||
| 60 | |||
| 61 | /** |
||
| 62 | * Switch to determine if navigation should display leaves or pages. |
||
| 63 | */ |
||
| 64 | public bool $list_leaves = true; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * List only the leaf elements or pages |
||
| 68 | */ |
||
| 69 | public bool $list_nodes = true; |
||
| 70 | |||
| 71 | /** |
||
| 72 | * Switch to determine if navigation should follow node path (on true) or stop on the |
||
| 73 | * spot. |
||
| 74 | */ |
||
| 75 | public bool $follow_selected = true; |
||
| 76 | |||
| 77 | /** |
||
| 78 | * Switch to determine if navigation should follow all the nodes or only the current |
||
| 79 | */ |
||
| 80 | public bool $follow_all = false; |
||
| 81 | |||
| 82 | /** |
||
| 83 | * Restrict the amount of levels listed. |
||
| 84 | */ |
||
| 85 | public int $list_levels = 0; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * ID of the root level list object |
||
| 89 | */ |
||
| 90 | public ?string $root_object_id = null; |
||
| 91 | |||
| 92 | /** |
||
| 93 | * CSS class for styling the lists |
||
| 94 | */ |
||
| 95 | public string $css_list_style = 'fi_protie_navigation'; |
||
| 96 | |||
| 97 | /** |
||
| 98 | * Add component name to list item ul class name |
||
| 99 | */ |
||
| 100 | public bool $component_name_to_class = false; |
||
| 101 | |||
| 102 | /** |
||
| 103 | * Check if item has children and if so, add node/leaf class to list item |
||
| 104 | */ |
||
| 105 | public bool $has_children_to_class = false; |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Should the object's status be added to list item ul class names |
||
| 109 | * Since this forces us to load the entire object, set it to false if you don't need it |
||
| 110 | */ |
||
| 111 | public bool $object_status_to_class = false; |
||
| 112 | |||
| 113 | /** |
||
| 114 | * CSS class for nodes |
||
| 115 | */ |
||
| 116 | public string $css_node = 'node'; |
||
| 117 | |||
| 118 | /** |
||
| 119 | * CSS class for leaves |
||
| 120 | */ |
||
| 121 | public string $css_leaf = 'leaf'; |
||
| 122 | |||
| 123 | /** |
||
| 124 | * CSS class for the elements in node path. All the elements in node path will have this class. |
||
| 125 | */ |
||
| 126 | public string $css_selected = 'selected'; |
||
| 127 | |||
| 128 | /** |
||
| 129 | * CSS class for the current, active node or leaf. There can be only one active element. |
||
| 130 | */ |
||
| 131 | public string $css_active = 'active'; |
||
| 132 | |||
| 133 | /** |
||
| 134 | * CSS class for links |
||
| 135 | */ |
||
| 136 | public string $css_link = 'link'; |
||
| 137 | |||
| 138 | /** |
||
| 139 | * Here we initialize the classes and variables needed through the class. |
||
| 140 | */ |
||
| 141 | 9 | public function __construct(?int $id = null) |
|
| 142 | { |
||
| 143 | 9 | $this->_nap = new midcom_helper_nav(); |
|
| 144 | 9 | $this->get_node_path(); |
|
| 145 | |||
| 146 | 9 | if ($id !== null) { |
|
| 147 | $this->root_id = $id; |
||
| 148 | } |
||
| 149 | } |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Traverses through the node path to fetch the location of the current navigation access point. |
||
| 153 | */ |
||
| 154 | 9 | private function get_node_path() |
|
| 155 | { |
||
| 156 | // Get nodes |
||
| 157 | 9 | $this->node_path = $this->_nap->get_node_path(); |
|
| 158 | |||
| 159 | // If NAP offers a leaf it should be stored in the node path |
||
| 160 | 9 | if ($leaf = $this->_nap->get_current_leaf()) { |
|
| 161 | $this->node_path[] = $leaf; |
||
| 162 | } |
||
| 163 | } |
||
| 164 | |||
| 165 | /** |
||
| 166 | * Traverse the child elements starting from the requested node id |
||
| 167 | */ |
||
| 168 | 9 | private function _list_child_elements(int $id) |
|
| 169 | { |
||
| 170 | 9 | if (!$this->list_leaves) { |
|
| 171 | $children = $this->_nap->get_nodes($id); |
||
| 172 | 9 | } elseif (!$this->list_nodes) { |
|
| 173 | $children = $this->_nap->get_leaves($id); |
||
| 174 | } else { |
||
| 175 | 9 | $children = $this->_nap->list_child_elements($id); |
|
| 176 | } |
||
| 177 | |||
| 178 | // Stop traversing the path if there are no children |
||
| 179 | 9 | if (!$children) { |
|
| 180 | 9 | return; |
|
| 181 | } |
||
| 182 | |||
| 183 | // Add ID property to the first unordered list ever called |
||
| 184 | $element_id = ''; |
||
| 185 | if ($this->root_object_id) { |
||
| 186 | $element_id = " id=\"{$this->root_object_id}\""; |
||
| 187 | $this->root_object_id = null; |
||
| 188 | } |
||
| 189 | |||
| 190 | echo "<ul class=\"{$this->css_list_style} node-{$id}\"{$element_id}>"; |
||
| 191 | |||
| 192 | // Draw each child element |
||
| 193 | foreach ($children as $child) { |
||
| 194 | $this->_display_element($child); |
||
| 195 | } |
||
| 196 | |||
| 197 | echo "</ul>"; |
||
| 198 | } |
||
| 199 | |||
| 200 | private function _get_css_classes(array $item) : string |
||
| 201 | { |
||
| 202 | $classes = []; |
||
| 203 | |||
| 204 | if ($item[MIDCOM_NAV_TYPE] === 'node') { |
||
| 205 | if ( $item[MIDCOM_NAV_ID] === $this->_nap->get_current_node() |
||
| 206 | && ( !$this->_nap->get_current_leaf() |
||
| 207 | || !$this->_nap->get_leaf($this->_nap->get_current_leaf()))) { |
||
| 208 | $classes[] = $this->css_active; |
||
| 209 | } |
||
| 210 | |||
| 211 | if (in_array($item[MIDCOM_NAV_ID], $this->node_path, true)) { |
||
| 212 | $classes[] = $this->css_selected; |
||
| 213 | } |
||
| 214 | |||
| 215 | if ($this->component_name_to_class) { |
||
| 216 | $classes[] = str_replace('.', '_', $item[MIDCOM_NAV_COMPONENT]); |
||
| 217 | } |
||
| 218 | } elseif ($item[MIDCOM_NAV_ID] === $this->_nap->get_current_leaf()) { |
||
| 219 | // Place the corresponding css class for the currently active leaf) |
||
| 220 | $classes[] = $this->css_active; |
||
| 221 | $classes[] = $this->css_selected; |
||
| 222 | } |
||
| 223 | |||
| 224 | if ($this->has_children_to_class) { |
||
| 225 | if (!$this->list_leaves) { |
||
| 226 | $children = $this->_nap->get_nodes($item[MIDCOM_NAV_ID]); |
||
| 227 | } elseif ($item[MIDCOM_NAV_TYPE] == 'node') { |
||
| 228 | $children = $this->_nap->list_child_elements($item[MIDCOM_NAV_ID]); |
||
| 229 | } else { |
||
| 230 | $children = false; |
||
| 231 | } |
||
| 232 | $classes[] = $children ? $this->css_node : $this->css_leaf; |
||
| 233 | } |
||
| 234 | |||
| 235 | // Add information about the object's status |
||
| 236 | if ( $this->object_status_to_class |
||
| 237 | && isset($item[MIDCOM_NAV_OBJECT]) |
||
| 238 | && $css_status_class = midcom::get()->metadata->get_object_classes($item[MIDCOM_NAV_OBJECT])) { |
||
| 239 | $classes[] = $css_status_class; |
||
| 240 | } |
||
| 241 | |||
| 242 | return implode(' ', $classes); |
||
| 243 | } |
||
| 244 | |||
| 245 | private function _display_element(array $item) |
||
| 246 | { |
||
| 247 | $css_classes = $this->_get_css_classes($item); |
||
| 248 | // Finalize the class naming |
||
| 249 | $class = ($css_classes !== '') ? ' class="' . $css_classes . '"' : ''; |
||
| 250 | $link_class = $this->css_link ? ' class="' . $this->css_link . '"' : ''; |
||
| 251 | |||
| 252 | echo "<li{$class}>"; |
||
| 253 | echo "<a href=\"{$item[MIDCOM_NAV_ABSOLUTEURL]}\"{$link_class}>" . htmlspecialchars($item[MIDCOM_NAV_NAME]) . "</a>"; |
||
| 254 | // If either of the follow nodes switches is on, follow all the nodes |
||
| 255 | |||
| 256 | if ( $item[MIDCOM_NAV_TYPE] === 'node' |
||
| 257 | && ( $this->list_levels === 0 |
||
| 258 | || $this->_level < $this->list_levels)) { |
||
| 259 | if ( $this->follow_all |
||
| 260 | || ( $this->follow_selected |
||
| 261 | && in_array($item[MIDCOM_NAV_ID], $this->node_path, true))) { |
||
| 262 | $this->_level++; |
||
| 263 | $this->_list_child_elements($item[MIDCOM_NAV_ID]); |
||
| 264 | $this->_level--; |
||
| 265 | } |
||
| 266 | } |
||
| 267 | |||
| 268 | echo "</li>"; |
||
| 269 | } |
||
| 270 | |||
| 271 | /** |
||
| 272 | * Draw the navigation. |
||
| 273 | */ |
||
| 274 | 9 | public function draw() |
|
| 275 | { |
||
| 276 | 9 | if (!$this->list_leaves && !$this->list_nodes) { |
|
| 277 | return; |
||
| 278 | } |
||
| 279 | 9 | if (!$this->root_id) { |
|
|
0 ignored issues
–
show
|
|||
| 280 | 9 | $this->root_id = $this->_nap->get_root_node(); |
|
| 281 | } |
||
| 282 | |||
| 283 | 9 | if ($this->skip_levels !== 0) { |
|
| 284 | if (!array_key_exists($this->skip_levels, $this->node_path)) { |
||
| 285 | return; |
||
| 286 | } |
||
| 287 | |||
| 288 | $this->root_id = $this->node_path[$this->skip_levels]; |
||
| 289 | } |
||
| 290 | |||
| 291 | 9 | $this->_list_child_elements($this->root_id); |
|
| 292 | } |
||
| 293 | |||
| 294 | /** |
||
| 295 | * Set the root element id |
||
| 296 | * |
||
| 297 | * @param string $id root ul id |
||
| 298 | */ |
||
| 299 | public function set_root_element_id(string $id) |
||
| 300 | { |
||
| 301 | $this->root_object_id = $id; |
||
| 302 | } |
||
| 303 | } |
||
| 304 |
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
integervalues, zero is a special case, in particular the following results might be unexpected: