1<?php
2/*
3 +-------------------------------------------------------------------------+
4 | Copyright (C) 2004-2021 The Cacti Group                                 |
5 |                                                                         |
6 | This program is free software; you can redistribute it and/or           |
7 | modify it under the terms of the GNU General Public License             |
8 | as published by the Free Software Foundation; either version 2          |
9 | of the License, or (at your option) any later version.                  |
10 |                                                                         |
11 | This program is distributed in the hope that it will be useful,         |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
14 | GNU General Public License for more details.                            |
15 +-------------------------------------------------------------------------+
16 | Cacti: The Complete RRDtool-based Graphing Solution                     |
17 +-------------------------------------------------------------------------+
18 | This code is designed, written, and maintained by the Cacti Group. See  |
19 | about.php and/or the AUTHORS file for specific developer information.   |
20 +-------------------------------------------------------------------------+
21 | http://www.cacti.net/                                                   |
22 +-------------------------------------------------------------------------+
23*/
24
25/* html_start_box - draws the start of an HTML box with an optional title
26   @arg $title - the title of this box ("" for no title)
27   @arg $width - the width of the box in pixels or percent
28   @arg $div - end with a starting div
29   @arg $cell_padding - the amount of cell padding to use inside of the box
30   @arg $align - the HTML alignment to use for the box (center, left, or right)
31   @arg $add_text - the url to use when the user clicks 'Add' in the upper-right
32        corner of the box ("" for no 'Add' link)
33        This function has two method.  This first is for legacy behavior where you
34        you pass in a href to the function, and an optional label as $add_label
35        The new format accepts an array of hrefs to add to the start box.  The format
36        of the array is as follows:
37
38        $add_text = array(
39            array(
40                'id' => 'uniqueid',
41                'href' => 'value',
42                'title' => 'title',
43                'callback' => true|false,
44                'class' => 'fa fa-icon'
45            ),
46            ...
47        );
48
49        If the callback is true, the Cacti attribute will be added to the href
50        to present only the contents and not to include both the headers.  If
51        the link must go off page, simply make sure $callback is false.  There
52        is a requirement to use fontawesome icon sets for this class, but it
53        can include other classes.  In addition, the href can be a hash '#' if
54        your page has a ready function that has it's own javascript.
55   @arg $add_label - used with legacy behavior to add specific text to the link.
56        This parameter is only used in the legacy behavior.
57 */
58function html_start_box($title, $width, $div, $cell_padding, $align, $add_text, $add_label = false) {
59	static $table_suffix = 1;
60	static $help_count   = 0;
61
62	if ($add_label === false) {
63		$add_label = __('Add');
64	}
65
66	if (defined('CACTI_VERSION_BETA') && $title != '') {
67		$title .= ' [ ' . get_cacti_version_text(false) . ' ]';
68	}
69
70	$table_prefix = basename(get_current_page(), '.php');;
71	if (!isempty_request_var('action')) {
72		$table_prefix .= '_' . clean_up_name(get_nfilter_request_var('action'));
73	} elseif (!isempty_request_var('report')) {
74		$table_prefix .= '_' . clean_up_name(get_nfilter_request_var('report'));
75	} elseif (!isempty_request_var('tab')) {
76		$table_prefix .= '_' . clean_up_name(get_nfilter_request_var('tab'));
77	}
78	$table_id = $table_prefix . $table_suffix;
79
80	if ($title != '') {
81		print "<div id='$table_id' class='cactiTable' style='width:$width;text-align:$align;'>";
82		print '<div>';
83		print "<div class='cactiTableTitle'><span>" . ($title != '' ? $title:'') . '</span></div>';
84		print "<div class='cactiTableButton'>";
85
86		$page      = get_current_page();
87		$help_file = html_help_page($page);
88
89		if ($help_file === false) {
90			if (isset_request_var('tab')) {
91				$tpage     = $page . ':' . get_nfilter_request_var('tab');
92				$help_file = html_help_page($tpage);
93			}
94		}
95
96		if ($help_file === false) {
97			if (isset_request_var('action')) {
98				$tpage     = $page . ':' . get_nfilter_request_var('action');
99				$help_file = html_help_page($tpage);
100			}
101		}
102
103		if ($help_file !== false && $help_count == 0 && is_realm_allowed(28)) {
104			print "<span class='cactiHelp' title='" . __esc('Get Page Help') . "'><a class='linkOverDark' target='_blank' href='" . html_escape($help_file) . "'><i class='far fa-question-circle'></i></a></span>";
105			$help_count++;
106		}
107
108		if ($add_text != '' && !is_array($add_text)) {
109			print "<span class='cactiFilterAdd' title='$add_label'><a class='linkOverDark' href='" . html_escape($add_text) . "'><i class='fa fa-plus'></i></a></span>";
110		} else {
111			if (is_array($add_text)) {
112				if (cacti_sizeof($add_text)) {
113					foreach($add_text as $icon) {
114						if (isset($icon['callback']) && $icon['callback'] === true) {
115							$classo = 'linkOverDark';
116						} else {
117							$classo = '';
118						}
119
120						if (isset($icon['class']) && $icon['class'] !== '') {
121							$classi = $icon['class'];
122						} else {
123							$classi = 'fa fa-plus';
124						}
125
126						if (isset($icon['href'])) {
127							$href = html_escape($icon['href']);
128						} else {
129							$href = '#';
130						}
131
132						if (isset($icon['title'])) {
133							$title = $icon['title'];
134						} else {
135							$title = $add_label;
136						}
137
138						print "<span class='cactiFilterAdd' title='$title'><a" . (isset($icon['id']) ? " id='" . $icon['id'] . "'":'') . " class='$classo' href='$href'><i class='$classi'></i></a></span>";
139					}
140				}
141			} else {
142				print '<span> </span>';
143			}
144		}
145		print '</div></div>';
146
147		if ($div === true) {
148			print "<div id='$table_id" . "_child' class='cactiTable'>";
149		} else {
150			print "<table id='$table_id" . "_child' class='cactiTable' style='padding:" . $cell_padding . "px;'>";
151		}
152	} else {
153		print "<div id='$table_id' class='cactiTable' style='width:$width;text-align:$align;'>";
154
155		if ($div === true) {
156			print "<div id='$table_id" . "_child' class='cactiTable'>";
157		} else {
158			print "<table id='$table_id" . "_child' class='cactiTable' style='padding:" . $cell_padding . "px;'>";
159		}
160	}
161
162	$table_suffix++;
163}
164
165/* html_end_box - draws the end of an HTML box
166   @arg $trailing_br (bool) - whether to draw a trailing <br> tag after ending
167   @arg $div (bool) - whether type of box is div or table */
168function html_end_box($trailing_br = true, $div = false) {
169	if ($div) {
170		print '</div></div>';
171	} else {
172		print '</table></div>';
173	}
174
175	if ($trailing_br == true) {
176		print "<div class='break'></div>";
177	}
178}
179
180/* html_graph_template_multiselect - consistent multiselect javascript library for cacti. */
181function html_graph_template_multiselect() {
182	?>
183	var msWidth = 200;
184
185	$('#graph_template_id').hide().multiselect({
186		height: 300,
187		menuWidth: 'auto',
188		buttonWidth: 'auto',
189		noneSelectedText: '<?php print __('All Graphs & Templates');?>',
190		selectedText: function(numChecked, numTotal, checkedItems) {
191			myReturn = numChecked + ' <?php print __('Templates Selected');?>';
192			$.each(checkedItems, function(index, value) {
193				if (value.value == '-1') {
194					myReturn='<?php print __('All Graphs & Templates');?>';
195					return false;
196				} else if (value.value == '0') {
197					myReturn='<?php print __('Not Templated');?>';
198					return false;
199				}
200			});
201			return myReturn;
202		},
203		checkAllText: '<?php print __('All');?>',
204		uncheckAllText: '<?php print __('None');?>',
205		uncheckall: function() {
206			$(this).multiselect('widget').find(':checkbox:first').each(function() {
207				$(this).prop('checked', true);
208			});
209		},
210		close: function(event, ui) {
211			applyGraphFilter();
212		},
213		open: function(event, ui) {
214			$("input[type='search']:first").focus();
215		},
216		click: function(event, ui) {
217			checked=$(this).multiselect('widget').find('input:checked').length;
218
219			if (ui.value == -1 || ui.value == 0) {
220				if (ui.checked == true) {
221					$('#graph_template_id').multiselect('uncheckAll');
222					if (ui.value == -1) {
223						$(this).multiselect('widget').find(':checkbox:first').prop('checked', true);
224					} else {
225						$(this).multiselect('widget').find(':checkbox[value="0"]').prop('checked', true);
226					}
227				}
228			} else if (checked == 0) {
229				$(this).multiselect('widget').find(':checkbox:first').each(function() {
230					$(this).click();
231				});
232			} else if ($(this).multiselect('widget').find('input:checked:first').val() == '-1') {
233				if (checked > 0) {
234					$(this).multiselect('widget').find(':checkbox:first').each(function() {
235						$(this).click();
236						$(this).prop('disable', true);
237					});
238				}
239			} else {
240				$(this).multiselect('widget').find(':checkbox[value="0"]').prop('checked', false);
241			}
242		}
243	}).multiselectfilter({
244		label: '<?php print __('Search');?>',
245		placeholder: '<?php print __('Enter keyword');?>',
246		width: msWidth
247	});
248	<?php
249}
250
251/* html_graph_area - draws an area the contains full sized graphs
252   @arg $graph_array - the array to contains graph information. for each graph in the
253        array, the following two keys must exist
254        $arr[0]["local_graph_id"] // graph id
255        $arr[0]["title_cache"] // graph title
256   @arg $no_graphs_message - display this message if no graphs are found in $graph_array
257   @arg $extra_url_args - extra arguments to append to the url
258   @arg $header - html to use as a header
259   @arg $columns - the number of columns to present
260   @arg $tree_id - the tree id if this is a tree thumbnail
261   @arg $branch_id - the branch id if this is a tree thumbnail
262*/
263function html_graph_area(&$graph_array, $no_graphs_message = '', $extra_url_args = '', $header = '', $columns = 0, $tree_id = 0, $branch_id = 0) {
264	global $config;
265	$i = 0; $k = 0; $j = 0;
266
267	$num_graphs = cacti_sizeof($graph_array);
268
269	if ($columns == 0) {
270		$columns = read_user_setting('num_columns');
271	}
272
273	?>
274	<script type='text/javascript'>
275	var refreshMSeconds = <?php print read_user_setting('page_refresh')*1000;?>;
276	var graph_start     = <?php print get_current_graph_start();?>;
277	var graph_end       = <?php print get_current_graph_end();?>;
278	</script>
279	<?php
280
281	if ($num_graphs > 0) {
282		if ($header != '') {
283			print $header;
284		}
285
286		foreach ($graph_array as $graph) {
287			if ($i == 0) {
288				print "<tr class='tableRowGraph'>";
289			}
290
291			?>
292			<td style='width:<?php print round(100 / $columns, 2);?>%;'>
293				<div>
294				<table style='text-align:center;margin:auto;'>
295					<tr>
296						<td>
297							<div class='graphWrapper' style='width:100%;' id='wrapper_<?php print $graph['local_graph_id']?>' graph_width='<?php print $graph['width'];?>' graph_height='<?php print $graph['height'];?>' title_font_size='<?php print ((read_user_setting('custom_fonts') == 'on') ? read_user_setting('title_size') : read_config_option('title_size'));?>'></div>
298							<?php print (read_user_setting('show_graph_title') == 'on' ? "<span class='center'>" . html_escape($graph['title_cache']) . '</span>' : '');?>
299						</td>
300						<?php if (is_realm_allowed(27)) { ?><td id='dd<?php print $graph['local_graph_id'];?>' class='noprint graphDrillDown'>
301							<?php graph_drilldown_icons($graph['local_graph_id'], 'graph_buttons', $tree_id, $branch_id);?>
302						</td><?php } ?>
303					</tr>
304				</table>
305				<div>
306			</td>
307			<?php
308
309			$i++;
310
311			if (($i % $columns) == 0) {
312				$i = 0;
313				print '</tr>';
314			}
315		}
316
317		while(($i % $columns) != 0) {
318			print "<td style='text-align:center;width:" . round(100 / $columns, 2) . "%;'></td>";
319			$i++;
320		}
321
322		print '</tr>';
323	} else {
324		if ($no_graphs_message != '') {
325			print "<td><em>$no_graphs_message</em></td>";
326		}
327	}
328}
329
330/* html_graph_thumbnail_area - draws an area the contains thumbnail sized graphs
331   @arg $graph_array - the array to contains graph information. for each graph in the
332        array, the following two keys must exist
333        $arr[0]["local_graph_id"] // graph id
334        $arr[0]["title_cache"] // graph title
335   @arg $no_graphs_message - display this message if no graphs are found in $graph_array
336   @arg $extra_url_args - extra arguments to append to the url
337   @arg $header - html to use as a header
338   @arg $columns - the number of columns to present
339   @arg $tree_id - the tree id if this is a tree thumbnail
340   @arg $branch_id - the branch id if this is a tree thumbnail
341*/
342function html_graph_thumbnail_area(&$graph_array, $no_graphs_message = '', $extra_url_args = '', $header = '', $columns = 0, $tree_id = 0, $branch_id = 0) {
343	global $config;
344	$i = 0; $k = 0; $j = 0;
345
346	$num_graphs = cacti_sizeof($graph_array);
347
348	if ($columns == 0) {
349		$columns = read_user_setting('num_columns');
350	}
351
352	?>
353	<script type='text/javascript'>
354	var refreshMSeconds = <?php print read_user_setting('page_refresh')*1000;?>;
355	var graph_start     = <?php print get_current_graph_start();?>;
356	var graph_end       = <?php print get_current_graph_end();?>;
357	</script>
358	<?php
359
360	if ($num_graphs > 0) {
361		if ($header != '') {
362			print $header;
363		}
364
365		$start = true;
366		foreach ($graph_array as $graph) {
367			if (isset($graph['graph_template_name'])) {
368				if (isset($prev_graph_template_name)) {
369					if ($prev_graph_template_name != $graph['graph_template_name']) {
370						$prev_graph_template_name = $graph['graph_template_name'];
371					}
372				} else {
373					$prev_graph_template_name = $graph['graph_template_name'];
374				}
375			} elseif (isset($graph['data_query_name'])) {
376				if (isset($prev_data_query_name)) {
377					if ($prev_data_query_name != $graph['data_query_name']) {
378						$print  = true;
379						$prev_data_query_name = $graph['data_query_name'];
380					} else {
381						$print = false;
382					}
383				} else {
384					$print  = true;
385					$prev_data_query_name = $graph['data_query_name'];
386				}
387
388				if ($print) {
389					if (!$start) {
390						while(($i % $columns) != 0) {
391							print "<td style='text-align:center;width:" . round(100 / $columns, 3) . "%;'></td>";
392							$i++;
393						}
394
395						print '</tr>';
396					}
397
398					print "<tr class='tableHeader'>
399							<td class='graphSubHeaderColumn textHeaderDark' colspan='$columns'>" . __('Data Query:') . ' ' . $graph['data_query_name'] . '</td>
400						</tr>';
401					$i = 0;
402				}
403			}
404
405			if ($i == 0) {
406				print "<tr class='tableRowGraph'>";
407				$start = false;
408			}
409
410			?>
411			<td style='width:<?php print round(100 / $columns, 2);?>%;'>
412				<table style='text-align:center;margin:auto;'>
413					<tr>
414						<td>
415							<div class='graphWrapper' id='wrapper_<?php print $graph['local_graph_id']?>' graph_width='<?php print read_user_setting('default_width');?>' graph_height='<?php print read_user_setting('default_height');?>'></div>
416							<?php print (read_user_setting('show_graph_title') == 'on' ? "<span class='center'>" . html_escape($graph['title_cache']) . '</span>' : '');?>
417						</td>
418						<?php if (is_realm_allowed(27)) { ?><td id='dd<?php print $graph['local_graph_id'];?>' class='noprint graphDrillDown'>
419							<?php print graph_drilldown_icons($graph['local_graph_id'], 'graph_buttons_thumbnails', $tree_id, $branch_id);?>
420						</td><?php } ?>
421					</tr>
422				</table>
423			</td>
424			<?php
425
426			$i++;
427			$k++;
428
429			if (($i % $columns) == 0 && ($k < $num_graphs)) {
430				$i=0;
431				$j++;
432				print '</tr>';
433				$start = true;
434			}
435		}
436
437		if (!$start) {
438			while(($i % $columns) != 0) {
439				print "<td style='text-align:center;width:" . round(100 / $columns, 2) . "%;'></td>";
440				$i++;
441			}
442
443			print '</tr>';
444		}
445	} else {
446		if ($no_graphs_message != '') {
447			print "<td><em>$no_graphs_message</em></td>";
448		}
449	}
450}
451
452function graph_drilldown_icons($local_graph_id, $type = 'graph_buttons', $tree_id = 0, $branch_id = 0) {
453	global $config;
454	static $rand = 0;
455
456	$aggregate_url = aggregate_build_children_url($local_graph_id);
457
458	print "<div class='iconWrapper'>";
459	print "<a class='iconLink utils' href='#' role='link' id='graph_" . $local_graph_id . "_util'><img class='drillDown' src='" . $config['url_path'] . "images/cog.png' alt='' title='" . __esc('Graph Details, Zooming and Debugging Utilities') . "'></a><br>";
460	print "<a class='iconLink csvexport' href='#' role='link' id='graph_" . $local_graph_id . "_csv'><img class='drillDown' src='" . $config['url_path'] . "images/table_go.png' alt='' title='" . __esc('CSV Export of Graph Data'). "'></a><br>";
461	print "<a class='iconLink mrgt' href='#' role='link' id='graph_" . $local_graph_id . "_mrtg'><img class='drillDown' src='" . $config['url_path'] . "images/timeview.png' alt='' title='" . __esc('Time Graph View'). "'></a><br>";
462
463	if (is_realm_allowed(3)) {
464		$host_id = db_fetch_cell_prepared('SELECT host_id
465			FROM graph_local
466			WHERE id = ?',
467			array($local_graph_id));
468
469		if ($host_id > 0) {
470			print "<a class='iconLink' href='" . html_escape($config['url_path'] . "host.php?action=edit&id=$host_id") . "' data-graph='" . $local_graph_id . "' id='graph_" . $local_graph_id . "_de'><img id='de" . $host_id . '_' . $rand . "' class='drillDown' src='" . $config['url_path'] . "images/server_edit.png' title='" . __esc('Edit Device') . "'></a>";
471			print '<br/>';
472			$rand++;
473		}
474	}
475
476	if (read_config_option('realtime_enabled') == 'on' && is_realm_allowed(25)) {
477		if (read_user_setting('realtime_mode') == '' || read_user_setting('realtime_mode') == '1') {
478			print "<a class='iconLink realtime' href='#' role='link' id='graph_" . $local_graph_id . "_realtime'><img class='drillDown' src='" . $config['url_path'] . "images/chart_curve_go.png' alt='' title='" . __esc('Click to view just this Graph in Real-time'). "'></a><br/>";
479		} else {
480			print "<a class='iconLink' href='#' onclick=\"window.open('" . $config['url_path'] . 'graph_realtime.php?top=0&left=0&local_graph_id=' . $local_graph_id . "', 'popup_" . $local_graph_id . "', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=650,height=300');return false\"><img src='" . $config['url_path'] . "images/chart_curve_go.png' alt='' title='" . __esc('Click to view just this Graph in Real-time') . "'></a><br/>";
481		}
482	}
483
484	if (is_realm_allowed(1043)) {
485		print "<span class='iconLink spikekill' data-graph='" . $local_graph_id . "' id='graph_" . $local_graph_id . "_sk'><img id='sk" . $local_graph_id . "' class='drillDown' src='" . $config['url_path'] . "images/spikekill.gif' title='" . __esc('Kill Spikes in Graphs') . "'></span>";
486		print '<br/>';
487	}
488
489	if ($aggregate_url != '') {
490		print $aggregate_url;
491	}
492
493	api_plugin_hook($type, array(
494		'hook' => $type,
495		'local_graph_id' => $local_graph_id,
496		'rra' =>  0,
497		'view_type' => $tree_id > 0 ? 'tree':'preview',
498		'tree_id' => $tree_id,
499		'branch_id' => $branch_id)
500	);
501
502	print '</div>';
503}
504
505/* html_nav_bar - draws a navigation bar which includes previous/next links as well as current
506	page information
507   @arg $base_url - the base URL will all filter options except page (should include url_path)
508   @arg $max_pages - the maximum number of pages to display
509   @arg $current_page - the current page in the navigation system
510   @arg $rows_per_page - the number of rows that are displayed on a single page
511   @arg $total_rows - the total number of rows in the navigation system
512   @arg $object - the object types that is being displayed
513   @arg $page_var - the object types that is being displayed
514   @arg $return_to - paint the resulting page into this dom object
515   @arg $page_count - provide a page count */
516function html_nav_bar($base_url, $max_pages, $current_page, $rows_per_page, $total_rows, $colspan=30, $object = '', $page_var = 'page', $return_to = '', $page_count = true) {
517	if ($object == '') $object = __('Rows');
518
519	if ($total_rows > $rows_per_page && $page_count) {
520		if (substr_count($base_url, '?') == 0) {
521			$base_url = trim($base_url) . '?';
522		} else {
523			$base_url = trim($base_url) . '&';
524		}
525
526		$url_page_select = get_page_list($current_page, $max_pages, $rows_per_page, $total_rows, $base_url, $page_var, $return_to);
527
528		$nav = "<div class='navBarNavigation'>
529			<div class='navBarNavigationPrevious'>
530				" . (($current_page > 1) ? "<a href='#' onClick='goto$page_var(" . ($current_page-1) . ");return false;'><i class='fa fa-angle-double-left previous'></i>" . __('Previous'). '</a>':'') . "
531			</div>
532			<div class='navBarNavigationCenter'>
533				" . __('%d to %d of %s [ %s ]', (($rows_per_page*($current_page-1))+1), (($total_rows < $rows_per_page) || ($total_rows < ($rows_per_page*$current_page)) ? $total_rows : $rows_per_page*$current_page), $total_rows, $url_page_select) . "
534			</div>
535			<div class='navBarNavigationNext'>
536				" . (($current_page*$rows_per_page) < $total_rows ? "<a href='#' onClick='goto$page_var(" . ($current_page+1) . ");return false;'>" . __('Next'). "<i class='fa fa-angle-double-right next'></i></a>":'') . "
537			</div>
538		</div>";
539	} elseif ($total_rows > 0) {
540		if ($page_count || ($total_rows < $rows_per_page && $current_page ==1) ) {
541			$nav = "<div class='navBarNavigation'>
542				<div class='navBarNavigationNone'>
543					" . __('All %d %s', $total_rows, $object) . "
544				</div>
545			</div>\n";
546		} else {
547			if (substr_count($base_url, '?') == 0) {
548				$base_url = trim($base_url) . '?';
549			} else {
550				$base_url = trim($base_url) . '&';
551			}
552
553			$url_page_select = "<ul class='pagination'>"; //for the same height as write in get_page_list()
554			$url_page_select .= "<li>$current_page</a></li>";
555			$url_page_select .= '</ul>';
556
557			$nav = "<div class='navBarNavigation'>
558				<div class='navBarNavigationPrevious'>
559					" . (($current_page > 1) ? "<a href='#' onClick='goto$page_var(" . ($current_page-1) . ");return false;'><i class='fa fa-angle-double-left previous'></i>" . __('Previous'). "</a>":"") . "
560				</div>
561				<div class='navBarNavigationCenter'>
562					" . __('Current Page: %s', $url_page_select) . "
563				</div>
564				<div class='navBarNavigationNext'>
565					" . ($total_rows >= $rows_per_page ? "<a href='#' onClick='goto$page_var(" . ($current_page+1) . ");return false;'>" . __('Next'). "<i class='fa fa-angle-double-right next'></i></a>":"") . "
566				</div>
567			</div>\n";
568
569			if ($return_to != '') {//code as in get_page_list()
570				$nav .= "<script type='text/javascript'>function goto$page_var(pageNo) { if (typeof url_graph === 'function') { var url_add=url_graph('') } else { var url_add=''; }; $.get('" . $base_url . "header=false&" . $page_var . "='+pageNo+url_add).done(function(data) { $('#$return_to').html(data); applySkin(); }); }</script>";
571			} else {
572				$nav .= "<script type='text/javascript'>function goto${page_var}(pageNo) { if (typeof url_graph === 'function') { var url_add=url_graph('') } else { var url_add=''; }; document.location='$base_url$page_var='+pageNo+url_add }</script>";
573			}
574		}
575	} else {
576		$nav = "<div class='navBarNavigation'>
577			<div class='navBarNavigationNone'>
578				" . __('No %s Found', $object) . '
579			</div>
580		</div>';
581	}
582
583	return $nav;
584}
585
586/* html_header_sort - draws a header row suitable for display inside of a box element.  When
587        a user selects a column header, the collback function "filename" will be called to handle
588        the sort the column and display the altered results.
589   @arg $header_items - an array containing a list of column items to display.  The
590        format is similar to the html_header, with the exception that it has three
591        dimensions associated with each element (db_column => display_text, default_sort_order)
592        alternatively (db_column => array('display' = 'blah', 'align' = 'blah', 'sort' = 'blah'))
593   @arg $sort_column - the value of current sort column.
594   @arg $sort_direction - the value the current sort direction.  The actual sort direction
595        will be opposite this direction if the user selects the same named column.
596   @arg $last_item_colspan - the TD 'colspan' to apply to the last cell in the row
597   @arg $url - a base url to redirect sort actions to
598   @arg $return_to - the id of the object to inject output into as a result of the sort action */
599function html_header_sort($header_items, $sort_column, $sort_direction, $last_item_colspan = 1, $url = '', $return_to = '') {
600	/* reverse the sort direction */
601	if ($sort_direction == 'ASC') {
602		$new_sort_direction = 'DESC';
603	} else {
604		$new_sort_direction = 'ASC';
605	}
606
607	$page = str_replace('.php', '', basename($_SERVER['SCRIPT_NAME']));
608	if (isset_request_var('action')) {
609		$page .= '_' . get_request_var('action');
610	}
611
612	if (isset_request_var('tab')) {
613		$page .= '_' . get_request_var('tab');
614	}
615
616	if (isset($_SESSION['sort_data'][$page])) {
617		$order_data = $_SESSION['sort_data'][$page];
618	} else {
619		$order_data = array(get_request_var('sort_column') => get_request_var('sort_direction'));
620	}
621
622	foreach($order_data as $key => $direction) {
623		$primarySort = $key;
624		break;
625	}
626
627	print "<tr class='tableHeader'>";
628
629	$i = 1;
630	foreach ($header_items as $db_column => $display_array) {
631		$isSort = '';
632		if (isset($display_array['nohide'])) {
633			$nohide = 'nohide';
634		} else {
635			$nohide = '';
636		}
637
638		if (array_key_exists('display', $display_array)) {
639			$display_text = $display_array['display'];
640			if ($sort_column == $db_column) {
641				$icon      = $sort_direction;
642				$direction = $new_sort_direction;
643
644				if ($db_column == $primarySort) {
645					$isSort = 'primarySort';
646				} else {
647					$isSort = 'secondarySort';
648				}
649			} else {
650				if (isset($order_data[$db_column])) {
651					$icon = $order_data[$db_column];
652					if ($order_data[$db_column] == 'DESC') {
653						$direction = 'ASC';
654					} else {
655						$direction = 'DESC';
656					}
657
658					if ($db_column == $primarySort) {
659						$isSort = 'primarySort';
660					} else {
661						$isSort = 'secondarySort';
662					}
663				} else {
664					$icon = '';
665					if (isset($display_array['sort'])) {
666						$direction = $display_array['sort'];
667					} else {
668						$direction = 'ASC';
669					}
670				}
671			}
672
673			if (isset($display_array['align'])) {
674				$align = $display_array['align'];
675			} else {
676				$align = 'left';
677			}
678
679			if (isset($display_array['tip'])) {
680				$tip = $display_array['tip'];
681			} else {
682				$tip = '';
683			}
684		} else {
685			/* by default, you will always sort ascending, with the exception of an already sorted column */
686			if ($sort_column == $db_column) {
687				$icon         = $sort_direction;
688				$direction    = $new_sort_direction;
689				$display_text = $display_array[0];
690
691				if ($db_column == $primarySort) {
692					$isSort = 'primarySort';
693				} else {
694					$isSort = 'secondarySort';
695				}
696			} else {
697				if (isset($order_data[$db_column])) {
698					$icon = $order_data[$db_column];
699					if ($order_data[$db_column] == 'DESC') {
700						$direction = 'ASC';
701					} else {
702						$direction = 'DESC';
703					}
704
705					if ($db_column == $primarySort) {
706						$isSort = 'primarySort';
707					} else {
708						$isSort = 'secondarySort';
709					}
710				} else {
711					$icon = '';
712					$direction = $display_array[1];
713				}
714
715				$display_text = $display_array[0];
716			}
717
718			$align = 'left';
719			$tip   = '';
720		}
721
722		if (strtolower($icon) == 'asc') {
723			$icon = 'fa fa-sort-up';
724		} elseif (strtolower($icon) == 'desc') {
725			$icon = 'fa fa-sort-down';
726		} else {
727			$icon = 'fa fa-sort';
728		}
729
730		if (($db_column == '') || (substr_count($db_column, 'nosort'))) {
731			print '<th ' . ($tip != '' ? "title='" . html_escape($tip) . "'":'') . " class='$nohide $align' " . ((($i+1) == cacti_count($header_items)) ? "colspan='$last_item_colspan' " : '') . '>' . $display_text . '</th>';
732		} else {
733			print '<th ' . ($tip != '' ? "title='" . html_escape($tip) . "'":'') . " class='sortable $align $nohide $isSort'>";
734			print "<div class='sortinfo' sort-return='" . ($return_to == '' ? 'main':$return_to) . "' sort-page='" . ($url == '' ? html_escape(get_current_page(false)):$url) . "' sort-column='$db_column' sort-direction='$direction'><div class='textSubHeaderDark'>" . $display_text . "<i class='$icon'></i></div></div></th>";
735		}
736
737		$i++;
738	}
739
740	print '</tr>';
741}
742
743/* html_header_sort_checkbox - draws a header row with a 'select all' checkbox in the last cell
744        suitable for display inside of a box element.  When a user selects a column header,
745        the collback function "filename" will be called to handle the sort the column and display
746        the altered results.
747   @arg $header_items - an array containing a list of column items to display.  The
748        format is similar to the html_header, with the exception that it has three
749        dimensions associated with each element (db_column => display_text, default_sort_order)
750        alternatively (db_column => array('display' = 'blah', 'align' = 'blah', 'sort' = 'blah'))
751   @arg $sort_column - the value of current sort column.
752   @arg $sort_direction - the value the current sort direction.  The actual sort direction
753        will be opposite this direction if the user selects the same named column.
754   @arg $form_action - the url to post the 'select all' form to
755   @arg $return_to - the id of the object to inject output into as a result of the sort action */
756function html_header_sort_checkbox($header_items, $sort_column, $sort_direction, $include_form = true, $form_action = '', $return_to = '') {
757	static $page = 0;
758
759	/* reverse the sort direction */
760	if ($sort_direction == 'ASC') {
761		$new_sort_direction = 'DESC';
762	} else {
763		$new_sort_direction = 'ASC';
764	}
765
766	$page = str_replace('.php', '', basename($_SERVER['SCRIPT_NAME']));
767	if (isset_request_var('action')) {
768		$page .= '_' . get_request_var('action');
769	}
770
771	if (isset_request_var('tab')) {
772		$page .= '_' . get_request_var('tab');
773	}
774
775	if (isset($_SESSION['sort_data'][$page])) {
776		$order_data = $_SESSION['sort_data'][$page];
777	} else {
778		$order_data = array(get_request_var('sort_column') => get_request_var('sort_direction'));
779	}
780
781	foreach($order_data as $key => $direction) {
782		$primarySort = $key;
783		break;
784	}
785
786	/* default to the 'current' file */
787	if ($form_action == '') { $form_action = get_current_page(); }
788
789	print "<tr class='tableHeader'>";
790
791	foreach($header_items as $db_column => $display_array) {
792		$isSort = '';
793		if (isset($display_array['nohide'])) {
794			$nohide = 'nohide';
795		} else {
796			$nohide = '';
797		}
798
799		$icon   = '';
800		if (array_key_exists('display', $display_array)) {
801			$display_text = $display_array['display'];
802			if ($sort_column == $db_column) {
803				$icon      = $sort_direction;
804				$direction = $new_sort_direction;
805
806				if ($db_column == $primarySort) {
807					$isSort = 'primarySort';
808				} else {
809					$isSort = 'secondarySort';
810				}
811			} else {
812				if (isset($order_data[$db_column])) {
813					$icon = $order_data[$db_column];
814					if ($order_data[$db_column] == 'DESC') {
815						$direction = 'ASC';
816					} else {
817						$direction = 'DESC';
818					}
819
820					if ($db_column == $primarySort) {
821						$isSort = 'primarySort';
822					} else {
823						$isSort = 'secondarySort';
824					}
825				} else {
826					$icon = '';
827					if (isset($display_array['sort'])) {
828						$direction = $display_array['sort'];
829					} else {
830						$direction = 'ASC';
831					}
832				}
833			}
834
835			if (isset($display_array['align'])) {
836				$align = $display_array['align'];
837			} else {
838				$align = 'left';
839			}
840
841			if (isset($display_array['tip'])) {
842				$tip = $display_array['tip'];
843			} else {
844				$tip = '';
845			}
846		} else {
847			/* by default, you will always sort ascending, with the exception of an already sorted column */
848			if ($sort_column == $db_column) {
849				$icon         = $sort_direction;
850				$direction    = $new_sort_direction;
851				$display_text = $display_array[0];
852
853				if ($db_column == $primarySort) {
854					$isSort = 'primarySort';
855				} else {
856					$isSort = 'secondarySort';
857				}
858			} else {
859				if (isset($order_data[$db_column])) {
860					$icon = $order_data[$db_column];
861					if ($order_data[$db_column] == 'DESC') {
862						$direction = 'ASC';
863					} else {
864						$direction = 'DESC';
865					}
866
867					if ($db_column == $primarySort) {
868						$isSort = 'primarySort';
869					} else {
870						$isSort = 'secondarySort';
871					}
872				} else {
873					$icon = '';
874					$direction = $display_array[1];
875				}
876
877				$display_text = $display_array[0];
878			}
879
880			$align = 'left';
881			$tip   = '';
882		}
883
884		if (strtolower($icon) == 'asc') {
885			$icon = 'fa fa-sort-up';
886		} elseif (strtolower($icon) == 'desc') {
887			$icon = 'fa fa-sort-down';
888		} else {
889			$icon = 'fa fa-sort';
890		}
891
892		if (($db_column == '') || (substr_count($db_column, 'nosort'))) {
893			print '<th ' . ($tip != '' ? "title='" . html_escape($tip) . "'":'') . " class='$align $nohide'>" . $display_text . '</th>';
894		} else {
895			print '<th ' . ($tip != '' ? "title='" . html_escape($tip) . "'":'') . " class='sortable $align $nohide $isSort'>";
896			print "<div class='sortinfo' sort-return='" . ($return_to == '' ? 'main':$return_to) . "' sort-page='" . html_escape($form_action) . "' sort-column='$db_column' sort-direction='$direction'><div class='textSubHeaderDark'>" . $display_text . "<i class='$icon'></i></div></div></th>";
897		}
898	}
899
900	print "<th class='tableSubHeaderCheckbox'><input id='selectall' class='checkbox' type='checkbox' title='" . __esc('Select All Rows'). "' onClick='selectAll(\"chk\",this.checked)'><label class='formCheckboxLabel' title='" . __esc('Select All Rows') . "' for='selectall'></label></th>" . ($include_form ? "<th style='display:none;'><form id='chk' name='chk' method='post' action='$form_action'></th>":'');
901	print '</tr>';
902
903	$page++;
904}
905
906/* html_header - draws a header row suitable for display inside of a box element
907   @arg $header_items - an array containing a list of items to be included in the header
908        alternatively and array of header names and alignment array('display' = 'blah', 'align' = 'blah')
909   @arg $last_item_colspan - the TD 'colspan' to apply to the last cell in the row */
910function html_header($header_items, $last_item_colspan = 1) {
911	print "<tr class='tableHeader " . (!$last_item_colspan > 1 ? 'tableFixed':'') . "'>";
912
913	$i = 0;
914	foreach($header_items as $item) {
915		if (is_array($item)) {
916			if (isset($item['nohide'])) {
917				$nohide = 'nohide';
918			} else {
919				$nohide = '';
920			}
921
922			if (isset($item['align'])) {
923				$align = $item['align'];
924			} else {
925				$align = 'left';
926			}
927
928			if (isset($item['tip'])) {
929				$tip = $item['tip'];
930			} else {
931				$tip = '';
932			}
933
934			print '<th ' . ($tip != '' ? "title='" . html_escape($tip) . "' ":'') . "class='$nohide $align' " . ((($i+1) == cacti_count($header_items)) ? "colspan='$last_item_colspan' " : '') . '>' . html_escape($item['display']) . '</th>';
935		} else {
936			print '<th ' . ((($i+1) == cacti_count($header_items)) ? "colspan='$last_item_colspan' " : '') . '>' . html_escape($item) . '</th>';
937		}
938
939		$i++;
940	}
941
942	print '</tr>';
943}
944
945/* html_section_header - draws a header row suitable for display inside of a box element
946         but for display as a secton title and not as a series of table header columns
947   @arg $header_name - an array of the display name of the header for the section and
948        optional alignment.
949   @arg $last_item_colspan - the TD 'colspan' to apply to the last cell in the row */
950function html_section_header($header_item, $last_item_colspan = 1) {
951	print "<tr class='tableHeader " . (!$last_item_colspan > 1 ? 'tableFixed':'') . "'>";
952
953	if (is_array($header_item) && isset($header_item['display'])) {
954		print "<th " . (isset($header_item['align']) ? "style='text-align:" . $header_item['align'] . ";'":"") . " colspan='$last_item_colspan'>" . $header_item['display'] . '</th>';
955	} else {
956		print "<th colspan='$last_item_colspan'>" . $header_item . '</th>';
957	}
958
959	print '</tr>';
960}
961
962/* html_header_checkbox - draws a header row with a 'select all' checkbox in the last cell
963        suitable for display inside of a box element
964   @arg $header_items - an array containing a list of items to be included in the header
965        alternatively and array of header names and alignment array('display' = 'blah', 'align' = 'blah')
966   @arg $form_action - the url to post the 'select all' form to */
967function html_header_checkbox($header_items, $include_form = true, $form_action = '', $resizable = true) {
968	/* default to the 'current' file */
969	if ($form_action == '') { $form_action = get_current_page(); }
970
971	print "<tr class='tableHeader " . (!$resizable ? 'tableFixed':'') . "'>";
972
973	foreach($header_items as $item) {
974		if (is_array($item)) {
975			if (isset($item['nohide'])) {
976				$nohide = 'nohide';
977			} else {
978				$nohide = '';
979			}
980
981			if (isset($item['align'])) {
982				$align = $item['align'];
983			} else {
984				$align = 'left';
985			}
986
987			if (isset($item['tip'])) {
988				$tip = $item['tip'];
989			} else {
990				$tip = '';
991			}
992
993			print '<th ' . ($tip != '' ? " title='" . html_escape($tip) . "' ":'') . "class='$align $nohide'>" . html_escape($item['display']) . '</th>';
994		} else {
995			print "<th class='left'>" . html_escape($item) . '</th>';
996		}
997	}
998
999	print "<th class='tableSubHeaderCheckbox'><input id='selectall' class='checkbox' type='checkbox' title='" . __esc('Select All Rows'). "' onClick='selectAll(\"chk\",this.checked)'><label class='formCheckboxLabel' title='" . __esc('Select All') . "' for='selectall'></label></th>" . ($include_form ? "<th style='display:none;'><form id='chk' name='chk' method='post' action='$form_action'></th>":'');
1000	print '</tr>';
1001}
1002
1003/* html_create_list - draws the items for an html dropdown given an array of data
1004   @arg $form_data - an array containing data for this dropdown. it can be formatted
1005        in one of two ways:
1006        $array["id"] = "value";
1007        -- or --
1008        $array[0]["id"] = 43;
1009        $array[0]["name"] = "Red";
1010   @arg $column_display - used to indentify the key to be used for display data. this
1011        is only applicable if the array is formatted using the second method above
1012   @arg $column_id - used to indentify the key to be used for id data. this
1013        is only applicable if the array is formatted using the second method above
1014   @arg $form_previous_value - the current value of this form element */
1015function html_create_list($form_data, $column_display, $column_id, $form_previous_value) {
1016	if (empty($column_display)) {
1017		if (cacti_sizeof($form_data)) {
1018			foreach (array_keys($form_data) as $id) {
1019				print '<option value="' . html_escape($id) . '"';
1020
1021				if ($form_previous_value == $id) {
1022					print ' selected';
1023				}
1024
1025				print '>' . html_escape(null_out_substitutions($form_data[$id])) . '</option>';
1026			}
1027		}
1028	} else {
1029		if (cacti_sizeof($form_data)) {
1030			foreach ($form_data as $row) {
1031				print "<option value='" . html_escape($row[$column_id]) . "'";
1032
1033				if ($form_previous_value == $row[$column_id]) {
1034					print ' selected';
1035				}
1036
1037				if (isset($row['host_id'])) {
1038					print '>' . html_escape($row[$column_display]) . '</option>';
1039				} else {
1040					print '>' . html_escape(null_out_substitutions($row[$column_display])) . '</option>';
1041				}
1042			}
1043		}
1044	}
1045}
1046
1047/* html_escape_request_var - sanitizes a request variable for display
1048   @arg $string - string the request variable to escape
1049   @returns $new_string - the escaped request variable to be returned. */
1050function html_escape_request_var($string) {
1051	return html_escape(get_request_var($string));
1052}
1053
1054/* html_escape - sanitizes a string for display
1055   @arg $string - string the string to escape
1056   @returns $new_string - the escaped string to be returned. */
1057function html_escape($string) {
1058	static $charset;
1059
1060	if ($charset == '') {
1061		$charset = ini_get('default_charset');
1062	}
1063
1064	if ($charset == '') {
1065		$charset = 'UTF-8';
1066	}
1067
1068	// Grave Accent character can lead to xss
1069	$string = str_replace('`', '&#96;', $string);
1070
1071	return htmlspecialchars($string, ENT_QUOTES|ENT_HTML5, $charset, false);
1072}
1073
1074/* html_split_string - takes a string and breaks it into a number of <br> separated segments
1075   @arg $string - string to be modified and returned
1076   @arg $length - the maximal string length to split to
1077   @arg $forgiveness - the maximum number of characters to walk back from to determine
1078        the correct break location.
1079   @returns $new_string - the modified string to be returned. */
1080function html_split_string($string, $length = 90, $forgiveness = 10) {
1081	$new_string = '';
1082	$j    = 0;
1083	$done = false;
1084
1085	while (!$done) {
1086		if (mb_strlen($string, 'UTF-8') > $length) {
1087			for($i = 0; $i < $forgiveness; $i++) {
1088				if (substr($string, $length-$i, 1) == ' ') {
1089					$new_string .= mb_substr($string, 0, $length-$i, 'UTF-8') . '<br>';
1090
1091					break;
1092				}
1093			}
1094
1095			$string = mb_substr($string, $length-$i, NULL, 'UTF-8');
1096		} else {
1097			$new_string .= $string;
1098			$done        = true;
1099		}
1100
1101		$j++;
1102		if ($j > 4) break;
1103	}
1104
1105	return $new_string;
1106}
1107
1108/* draw_graph_items_list - draws a nicely formatted list of graph items for display
1109        on an edit form
1110   @arg $item_list - an array representing the list of graph items. this array should
1111        come directly from the output of db_fetch_assoc()
1112   @arg $filename - the filename to use when referencing any external url
1113   @arg $url_data - any extra GET url information to pass on when referencing any
1114        external url
1115   @arg $disable_controls - whether to hide all edit/delete functionality on this form */
1116function draw_graph_items_list($item_list, $filename, $url_data, $disable_controls) {
1117	global $config;
1118
1119	include($config['include_path'] . '/global_arrays.php');
1120
1121	print "<tr class='tableHeader'>";
1122		DrawMatrixHeaderItem(__('Graph Item'),'',1);
1123		DrawMatrixHeaderItem(__('#'), '', 1);
1124		DrawMatrixHeaderItem(__('Data Source'),'',1);
1125		DrawMatrixHeaderItem(__('Graph Item Type'),'',1);
1126		DrawMatrixHeaderItem(__('CF Type'),'',1);
1127		DrawMatrixHeaderItem(__('GPrint'),'',1);
1128		DrawMatrixHeaderItem(__('CDEF'),'',1);
1129		DrawMatrixHeaderItem(__('VDEF'),'',1);
1130		DrawMatrixHeaderItem(__('Alpha %'),'',1);
1131		DrawMatrixHeaderItem(__('Item Color'),'',4);
1132	print '</tr>';
1133
1134	$group_counter = 0; $_graph_type_name = ''; $i = 0;
1135
1136	if (cacti_sizeof($item_list)) {
1137		foreach ($item_list as $item) {
1138			/* graph grouping display logic */
1139			$this_row_style   = '';
1140			$use_custom_class = false;
1141			$hard_return      = '';
1142
1143			if (!preg_match('/(GPRINT|TEXTALIGN|HRULE|VRULE|TICK)/', $graph_item_types[$item['graph_type_id']])) {
1144				$this_row_style = 'font-weight: bold;';
1145				$use_custom_class = true;
1146
1147				if ($group_counter % 2 == 0) {
1148					$customClass = 'graphItem';
1149				} else {
1150					$customClass = 'graphItemAlternate';
1151				}
1152
1153				$group_counter++;
1154			}
1155
1156			$_graph_type_name = $graph_item_types[$item['graph_type_id']];
1157
1158			/* alternating row color */
1159			if ($use_custom_class == false) {
1160				print "<tr class='tableRowGraph'>";
1161			} else {
1162				print "<tr class='tableRowGraph $customClass'>";
1163			}
1164
1165			print '<td>';
1166			if ($disable_controls == false) { print "<a class='linkEditMain' href='" . html_escape("$filename?action=item_edit&id=" . $item['id'] . "&$url_data") . "'>"; }
1167			print __('Item # %d', ($i+1));
1168			if ($disable_controls == false) { print '</a>'; }
1169			print '</td>';
1170			print '<td>' . $item['sequence'] . '</td>';
1171
1172			if (empty($item['data_source_name'])) {
1173				$item['data_source_name'] = __('No Source');
1174			}
1175
1176			switch (true) {
1177			case preg_match('/(TEXTALIGN)/', $_graph_type_name):
1178				$matrix_title = 'TEXTALIGN: ' . ucfirst($item['textalign']);
1179				break;
1180			case preg_match('/(TICK)/', $_graph_type_name):
1181				$matrix_title = $item['data_source_name'] . ': ' . $item['text_format'];
1182				break;
1183			case preg_match('/(AREA|STACK|GPRINT|LINE[123])/', $_graph_type_name):
1184				$matrix_title = $item['data_source_name'] . ': ' . $item['text_format'];
1185				break;
1186			case preg_match('/(HRULE)/', $_graph_type_name):
1187				$matrix_title = 'HRULE: ' . $item['value'];
1188				break;
1189			case preg_match('/(VRULE)/', $_graph_type_name):
1190				$matrix_title = 'VRULE: ' . $item['value'];
1191				break;
1192			case preg_match('/(COMMENT)/', $_graph_type_name):
1193				$matrix_title = 'COMMENT: ' . $item['text_format'];
1194				break;
1195			}
1196
1197			if (preg_match('/(TEXTALIGN)/', $_graph_type_name)) {
1198				$hard_return = '';
1199			} elseif ($item['hard_return'] == 'on') {
1200				$hard_return = "<span style='font-weight:bold;color:#FF0000;'>&lt;HR&gt;</span>";
1201			}
1202
1203			/* data source */
1204			print "<td style='$this_row_style'>" . html_escape($matrix_title) . $hard_return . '</td>';
1205
1206			/* graph item type */
1207			print "<td style='$this_row_style'>" . $graph_item_types[$item['graph_type_id']] . '</td>';
1208			if (!preg_match('/(TICK|TEXTALIGN|HRULE|VRULE)/', $_graph_type_name)) {
1209				print "<td style='$this_row_style'>" . $consolidation_functions[$item['consolidation_function_id']] . '</td>';
1210			} else {
1211				print '<td>' . __('N/A') . '</td>';
1212			}
1213
1214			print "<td style='$this_row_style'>";
1215			print $item['gprint_name'];
1216			print "</td>";
1217			print "<td style='$this_row_style'>";
1218			print $item['cdef_name'];
1219			print "</td>";
1220			print "<td style='$this_row_style'>";
1221			print $item['vdef_name'];
1222			print "</td>";
1223
1224			/* alpha type */
1225			if (preg_match('/(AREA|STACK|TICK|LINE[123])/', $_graph_type_name)) {
1226				print "<td style='$this_row_style'>" . round((hexdec($item['alpha'])/255)*100) . '%</td>';
1227			} else {
1228				print "<td style='$this_row_style'></td>";
1229			}
1230
1231			/* color name */
1232			if (!preg_match('/(TEXTALIGN)/', $_graph_type_name)) {
1233				print "<td style='width:1%;" . ((!empty($item['hex'])) ? 'background-color:#' . $item['hex'] . ";'" : "'") . '></td>';
1234				print "<td style='$this_row_style'>" . $item['hex'] . '</td>';
1235			} else {
1236				print '<td></td><td></td>';
1237			}
1238
1239			if ($disable_controls == false) {
1240				print "<td class='right nowrap'>";
1241
1242				if ($i != cacti_sizeof($item_list)-1) {
1243					print "<span><a class='moveArrow fa fa-caret-down' title='" . __esc('Move Down'). "' href='" . html_escape("$filename?action=item_movedown&id=" . $item['id'] . "&$url_data") . "'></a></span>";
1244				} else {
1245					print "<span class='moveArrowNone'></span>";
1246				}
1247
1248				if ($i > 0) {
1249					print "<span><a class='moveArrow fa fa-caret-up' title='" . __esc('Move Up') . "' href='" . html_escape("$filename?action=item_moveup&id=" . $item['id'] . "&$url_data") . "'></a></span>";
1250				} else {
1251					print "<span class='moveArrowNone'></span>";
1252				}
1253
1254				print '</td>';
1255
1256				print "<td style='width:1%' class='right'>";
1257
1258				print "<a class='deleteMarker fa fa-times' title='" . __esc('Delete') . "' href='" . html_escape("$filename?action=item_remove&id=" . $item['id'] . "&nostate=true&$url_data") . "'></a>";
1259
1260				print "</td>";
1261			}
1262
1263			print '</tr>';
1264
1265			$i++;
1266		}
1267	} else {
1268		print "<tr class='tableRow'><td colspan='7'><em>" . __('No Items') . '</em></td></tr>';
1269	}
1270}
1271
1272/* is_menu_pick_active - determines if current selection is active
1273   @arg $menu_url - url of current page
1274   @returns true if active, false if not
1275*/
1276function is_menu_pick_active($menu_url) {
1277	static $url_array, $url_parts;
1278
1279	$menu_parts = array();
1280
1281	/* special case for host.php?action=edit&create=true */
1282	if (strpos($_SERVER['REQUEST_URI'], 'host.php?action=edit&create=true') !== false) {
1283		if (strpos($menu_url, 'host.php?action=edit&create=true') !== false) {
1284			return true;
1285		} else {
1286			return false;
1287		}
1288	} elseif (strpos($_SERVER['REQUEST_URI'], 'graph_templates_items.php') !== false) {
1289		/* special case for Graph Template items edit */
1290		if (strpos($menu_url, 'graph_templates.php') !== false) {
1291			return true;
1292		} else {
1293			return false;
1294		}
1295	} elseif (strpos($_SERVER['REQUEST_URI'], 'graph_items.php') !== false) {
1296		/* special case for Graph items edit */
1297		if (strpos($menu_url, 'graphs.php') !== false) {
1298			return true;
1299		} else {
1300			return false;
1301		}
1302	} elseif (strpos($_SERVER['REQUEST_URI'], 'color_templates_items.php') !== false) {
1303		/* special case for Color Templates items edit */
1304		if (strpos($menu_url, 'color_templates.php') !== false) {
1305			return true;
1306		} else {
1307			return false;
1308		}
1309	} elseif (!is_array($url_array) || (is_array($url_array) && !cacti_sizeof($url_array))) {
1310		/* break out the URL and variables */
1311		$url_array = parse_url($_SERVER['REQUEST_URI']);
1312		if (isset($url_array['query'])) {
1313			parse_str($url_array['query'], $url_parts);
1314		} else {
1315			$url_parts = array();
1316		}
1317	}
1318
1319	// Host requires another check
1320	if (strpos($menu_url, 'host.php?action=edit&create=true') !== false) {
1321		return false;
1322	}
1323
1324	$menu_array = parse_url($menu_url);
1325	if ($menu_array === false) {
1326		return false;
1327	}
1328
1329	if (! array_key_exists('path', $menu_array)) {
1330		return false;
1331	}
1332
1333	if (basename($url_array['path']) == basename($menu_array['path'])) {
1334		if (isset($menu_array['query'])) {
1335			parse_str($menu_array['query'], $menu_parts);
1336		} else {
1337			$menu_parts = array();
1338		}
1339
1340		if (isset($menu_parts['id'])) {
1341			if (isset($url_parts['id'])) {
1342				if ($menu_parts['id'] == $url_parts['id']) {
1343					return true;
1344				}
1345			}
1346		} elseif (isset($menu_parts['action'])) {
1347			if (isset($url_parts['action'])) {
1348				if ($menu_parts['action'] == $url_parts['action']) {
1349					return true;
1350				}
1351			}
1352		} else {
1353			return true;
1354		}
1355	}
1356
1357	return false;
1358}
1359
1360/* draw_menu - draws the cacti menu for display in the console */
1361function draw_menu($user_menu = '') {
1362	global $config, $user_auth_realm_filenames, $menu, $menu_glyphs;
1363
1364	if (!is_array($user_menu)) {
1365		$user_menu = $menu;
1366	}
1367
1368	print "<tr><td><table width='100%'><tr><td><div id='menu'><ul id='nav' role='menu'>";
1369
1370	/* loop through each header */
1371	$i = 0;
1372	$headers = array();
1373	foreach ($user_menu as $header_name => $header_array) {
1374		/* pass 1: see if we are allowed to view any children */
1375		$show_header_items = false;
1376		foreach ($header_array as $item_url => $item_title) {
1377			if (preg_match('#link.php\?id=(\d+)#', $item_url, $matches)) {
1378				if (is_realm_allowed($matches[1]+10000)) {
1379					$show_header_items = true;
1380				} else {
1381					$show_header_items = false;
1382				}
1383			} else {
1384				$current_realm_id = (isset($user_auth_realm_filenames[basename($item_url)]) ? $user_auth_realm_filenames[basename($item_url)] : 0);
1385
1386				if (is_realm_allowed($current_realm_id)) {
1387					$show_header_items = true;
1388				} elseif (api_user_realm_auth(strtok($item_url, '?'))) {
1389					$show_header_items = true;
1390				}
1391			}
1392		}
1393
1394		if ($show_header_items == true) {
1395			// Let's give our menu li's a unique id
1396			$id = 'menu_' . strtolower(clean_up_name($header_name));
1397			if (isset($headers[$id])) {
1398				$id .= '_' . $i++;
1399			}
1400			$headers[$id] = true;
1401
1402			if (isset($menu_glyphs[$header_name])) {
1403				$glyph = '<i class="menu_glyph ' . $menu_glyphs[$header_name] . '"></i>';
1404			} else {
1405				$glyph = '<i class="menu_glyph fa fa-folder"></i>';
1406			}
1407
1408			print "<li class='menuitem' role='menuitem' aria-haspopup='true' id='$id'><a class='menu_parent active' href='#'>$glyph<span>$header_name</span></a>";
1409			print "<ul role='menu' id='${id}_div' style='display:block;'>";
1410
1411			/* pass 2: loop through each top level item and render it */
1412			foreach ($header_array as $item_url => $item_title) {
1413				$basename = explode('?', basename($item_url));
1414				$basename = $basename[0];
1415				$current_realm_id = (isset($user_auth_realm_filenames[$basename]) ? $user_auth_realm_filenames[$basename] : 0);
1416
1417				/* if this item is an array, then it contains sub-items. if not, is just
1418				the title string and needs to be displayed */
1419				if (is_array($item_title)) {
1420					$i = 0;
1421
1422					if ($current_realm_id == -1 || is_realm_allowed($current_realm_id) || !isset($user_auth_realm_filenames[$basename])) {
1423						/* if the current page exists in the sub-items array, draw each sub-item */
1424						if (array_key_exists(get_current_page(), $item_title) == true) {
1425							$draw_sub_items = true;
1426						} else {
1427							$draw_sub_items = false;
1428						}
1429
1430						foreach ($item_title as $item_sub_url => $item_sub_title) {
1431							if (substr($item_sub_url, 0, 10) == 'EXTERNAL::') {
1432								$item_sub_external = true;
1433								$item_sub_url = substr($item_sub_url, 10);
1434							} else {
1435								$item_sub_external = false;
1436								$item_sub_url = $config['url_path'] . $item_sub_url;
1437							}
1438
1439							/* always draw the first item (parent), only draw the children if we are viewing a page
1440							that is contained in the sub-items array */
1441							if (($i == 0) || ($draw_sub_items)) {
1442								if (is_menu_pick_active($item_sub_url)) {
1443									print "<li><a role='menuitem' class='pic selected' href='";
1444									print html_escape($item_sub_url) . "'";
1445									if ($item_sub_external) {
1446										print " target='_blank' rel='noopener'";
1447									}
1448									print ">$item_sub_title</a></li>";
1449								} else {
1450									print "<li><a role='menuitem' class='pic' href='";
1451									print html_escape($item_sub_url) . "'";
1452									if ($item_sub_external) {
1453										print " target='_blank' rel='noopener'";
1454									}
1455									print ">$item_sub_title</a></li>";
1456								}
1457							}
1458
1459							$i++;
1460						}
1461					}
1462				} else {
1463					if ($current_realm_id == -1 || is_realm_allowed($current_realm_id) || !isset($user_auth_realm_filenames[$basename])) {
1464						/* draw normal (non sub-item) menu item */
1465						if (substr($item_url, 0, 10) == 'EXTERNAL::') {
1466							$item_external = true;
1467							$item_url = substr($item_url, 10);
1468						} else {
1469							$item_external = false;
1470							$item_url = $config['url_path'] . $item_url;
1471						}
1472						if (is_menu_pick_active($item_url)) {
1473							print "<li><a role='menuitem' class='pic selected' href='";
1474							print html_escape($item_url) . "'";
1475							if ($item_external) {
1476								print " target='_blank' rel='noopener'";
1477							}
1478							print ">$item_title</a></li>";
1479						} else {
1480							print "<li><a role='menuitem' class='pic' href='";
1481							print html_escape($item_url) . "'";
1482							if ($item_external) {
1483								print " target='_blank' rel='noopener'";
1484							}
1485							print ">$item_title</a></li>";
1486						}
1487					}
1488				}
1489			}
1490
1491			print '</ul></li>';
1492		}
1493	}
1494
1495	print '</ul></div></td></tr></table></td></tr>';
1496}
1497
1498/* draw_actions_dropdown - draws a table the allows the user to select an action to perform
1499        on one or more data elements
1500   @arg $actions_array - an array that contains a list of possible actions. this array should
1501        be compatible with the form_dropdown() function
1502   @arg $delete_action - if there is a delete action that should surpress removal of rows
1503        specify it here.  If you don't want any delete actions, set to 0.*/
1504function draw_actions_dropdown($actions_array, $delete_action = 1) {
1505	global $config;
1506
1507	if ($actions_array === NULL || cacti_sizeof($actions_array) == 0) {
1508		return;
1509	}
1510
1511	if (!isset($actions_array[0])) {
1512		$my_actions[0]  = __('Choose an action');
1513		$my_actions    += $actions_array;
1514		$actions_array  = $my_actions;
1515	}
1516
1517	?>
1518	<div class='actionsDropdown'>
1519		<div>
1520			<span class='actionsDropdownArrow'><img src='<?php print $config['url_path']; ?>images/arrow.gif' alt=''></span>
1521			<?php form_dropdown('drp_action', $actions_array, '', '', '0', '', '');?>
1522			<span class='actionsDropdownButton'><input type='submit' class='ui-button ui-corner-all ui-widget' id='submit' value='<?php print __esc('Go');?>' title='<?php print __esc('Execute Action');?>'></span>
1523		</div>
1524	</div>
1525	<input type='hidden' id='action' name='action' value='actions'>
1526	<script type='text/javascript'>
1527
1528	function setDisabled() {
1529		$('tr[id^="line"]').addClass('selectable').prop('disabled', false).removeClass('disabled_row').unbind('click').prop('disabled', false);
1530
1531		if ($('#drp_action').val() == <?php print $delete_action;?>) {
1532			$(':checkbox.disabled').each(function(data) {
1533				$(this).closest('tr').addClass('disabled_row');
1534				if ($(this).is(':checked')) {
1535					$(this).prop('checked', false).removeAttr('aria-checked').removeAttr('data-prev-check');
1536					$(this).closest('tr').removeClass('selected');
1537				}
1538				$(this).prop('disabled', true).closest('tr').removeClass('selected');
1539			});
1540
1541			$('#submit').each(function() {
1542				if ($(this).button === 'function') {
1543					$(this).button('enable');
1544				} else {
1545					$(this).prop('disabled', false);
1546				}
1547			});
1548		} else if ($('#drp_action').val() == 0) {
1549			$(':checkbox.disabled').each(function(data) {
1550				$(this).prop('disabled', false);
1551			});
1552
1553			$('#submit').each(function() {
1554				if ($(this).button === 'function') {
1555					$(this).button('disable');
1556				} else {
1557					$(this).prop('disabled', true);
1558				}
1559			});
1560		} else if (<?php print $delete_action;?> != 0) {
1561			$('#submit').each(function() {
1562				if ($(this).button === 'function') {
1563					$(this).button('enable');
1564				} else {
1565					$(this).prop('disabled', false);
1566				}
1567			});
1568		}
1569
1570		$('tr[id^="line"]').filter(':not(.disabled_row)').off('click').on('click', function(event) {
1571			selectUpdateRow(event, $(this));
1572		});
1573	}
1574
1575	$(function() {
1576		setDisabled();
1577
1578		$('#drp_action').change(function() {
1579			setDisabled();
1580		});
1581
1582		$('.tableSubHeaderCheckbox').find(':checkbox').off('click').on('click', function(data) {
1583			if ($(this).is(':checked')) {
1584				$('input[id^="chk_"]').not(':disabled').prop('checked', true).attr('data-prev-check', 'true').attr('aria-checked', 'true');
1585				$('tr.selectable').addClass('selected');
1586				disableSelection();
1587			} else {
1588				$('input[id^="chk_"]').not(':disabled').prop('checked', false).removeAttr('data-prev-check').removeAttr('aria-checked');
1589				$('tr.selectable').removeClass('selected');
1590				enableSelection();
1591			}
1592		});
1593	});
1594	</script>
1595	<?php
1596}
1597
1598/*
1599 * Deprecated functions
1600 */
1601
1602function DrawMatrixHeaderItem($matrix_name, $matrix_text_color, $column_span = 1) {
1603	?>
1604	<th style='height:1px;' colspan='<?php print $column_span;?>'>
1605		<div class='textSubHeaderDark'><?php print $matrix_name;?></div>
1606	</th>
1607	<?php
1608}
1609
1610function form_area($text) { ?>
1611	<tr>
1612		<td class='textArea'>
1613			<?php print $text;?>
1614		</td>
1615	</tr>
1616<?php }
1617
1618/* is_console_page - determinese if current passed url is considered to be
1619          a console page
1620   @arg url - url to be checked
1621   @returns true if console page, false if not
1622*/
1623function is_console_page($url) {
1624	global $menu;
1625
1626	$basename = basename($url);
1627
1628	if ($basename == 'index.php') {
1629		return true;
1630	}
1631
1632	if ($basename == 'rrdcleaner.php') {
1633		return true;
1634	}
1635
1636	if (api_plugin_hook_function('is_console_page', $url) != $url) {
1637		return true;
1638	}
1639
1640	if (cacti_sizeof($menu)) {
1641		foreach($menu as $section => $children) {
1642			if (cacti_sizeof($children)) {
1643				foreach($children as $page => $name) {
1644					if (basename($page) == $basename) {
1645						return true;
1646					}
1647				}
1648			}
1649		}
1650	}
1651
1652	return false;
1653}
1654
1655function html_show_tabs_left() {
1656	global $config, $tabs_left;
1657
1658	$realm_allowed     = array();
1659	$realm_allowed[7]  = is_realm_allowed(7);
1660	$realm_allowed[8]  = is_realm_allowed(8);
1661	$realm_allowed[18] = is_realm_allowed(18);
1662	$realm_allowed[19] = is_realm_allowed(19);
1663	$realm_allowed[21] = is_realm_allowed(21);
1664	$realm_allowed[22] = is_realm_allowed(22);
1665
1666	if ($realm_allowed[8]) {
1667		$show_console_tab = true;
1668	} else {
1669		$show_console_tab = false;
1670	}
1671
1672	if (get_selected_theme() == 'classic') {
1673		if ($show_console_tab == true) {
1674			?><a id='tab-console' <?php print (is_console_page(get_current_page()) ? " class='selected'":'');?> href='<?php print $config['url_path']; ?>index.php'><img src='<?php echo $config['url_path']; ?>images/tab_console<?php print (is_console_page(get_current_page()) ? '_down':'');?>.gif' alt='<?php print __('Console');?>'></a><?php
1675		}
1676
1677		if ($realm_allowed[7]) {
1678			if ($config['poller_id'] > 1 && $config['connection'] != 'online') {
1679				// Don't show graphs tab when offline
1680			} else {
1681				$file = get_current_page();
1682				if ($file == 'graph_view.php' || $file == 'graph.php') {
1683					print "<a id='tab-graphs' class='selected' href='" . html_escape($config['url_path'] . 'graph_view.php') . "'><img src='" . $config['url_path'] . "images/tab_graphs_down.gif' alt='" . __('Graphs') . "'></a>";
1684				} else {
1685					print "<a id='tab-graphs' href='" . html_escape($config['url_path'] . 'graph_view.php') . "'><img src='" . $config['url_path'] . "images/tab_graphs.gif' alt='" . __('Graphs') . "'></a>";
1686				}
1687			}
1688		}
1689
1690		if ($realm_allowed[21] || $realm_allowed[22]) {
1691			if ($config['poller_id'] > 1) {
1692				// Don't show reports tabe if not poller 1
1693			} else {
1694				if (substr_count($_SERVER['REQUEST_URI'], 'reports_')) {
1695					print '<a id="tab-reports" href="' . $config['url_path'] . ($realm_allowed[22] ? 'reports_admin.php':'reports_user.php') . '"><img src="' . $config['url_path'] . 'images/tab_nectar_down.gif" alt="' . __('Reporting') . '"></a>';
1696				} else {
1697					print '<a id="tab-reports" href="' . $config['url_path'] . ($realm_allowed[22] ? 'reports_admin.php':'reports_user.php') . '"><img src="' . $config['url_path'] . 'images/tab_nectar.gif" alt="' . __('Reporting') . '"></a>';
1698				}
1699			}
1700		}
1701
1702		if ($realm_allowed[18] || $realm_allowed[19]) {
1703			if (substr_count($_SERVER['REQUEST_URI'], 'clog')) {
1704				print '<a id="tab-logs" href="' . $config['url_path'] . ($realm_allowed[18] ? 'clog.php':'clog_user.php') . '"><img src="' . $config['url_path'] . 'images/tab_clog_down.png" alt="' . __('Logs'). '"></a>';
1705			} else {
1706				print '<a id="tab-logs" href="' . $config['url_path'] . ($realm_allowed[18] ? 'clog.php':'clog_user.php') . '"><img src="' . $config['url_path'] . 'images/tab_clog.png" alt="' . __('Logs') . '"></a>';
1707			}
1708		}
1709
1710		api_plugin_hook('top_graph_header_tabs');
1711
1712		if ($config['poller_id'] > 1 && $config['connection'] != 'online') {
1713			// Only show external links when online
1714		} else {
1715			$external_links = db_fetch_assoc('SELECT id, title
1716				FROM external_links
1717				WHERE style="TAB"
1718				AND enabled="on"
1719				ORDER BY sortorder');
1720
1721			if (cacti_sizeof($external_links)) {
1722				foreach($external_links as $tab) {
1723					if (is_realm_allowed($tab['id']+10000)) {
1724						$parsed_url = parse_url($_SERVER['REQUEST_URI']);
1725						$down = false;
1726
1727						if (basename($parsed_url['path']) == 'link.php') {
1728							if (isset($parsed_url['query'])) {
1729								$queries = explode('&', $parsed_url['query']);
1730								foreach($queries as $q) {
1731									list($var, $value) = explode('=', $q);
1732									if ($var == 'id') {
1733										if ($value == $tab['id']) {
1734											$down = true;
1735											break;
1736										}
1737									}
1738								}
1739							}
1740						}
1741
1742						print '<a id="tab-link' . $tab['id'] . '" href="' . $config['url_path'] . 'link.php?id=' . $tab['id'] . '"><img src="' . get_classic_tabimage($tab['title'], $down) . '" alt="' . $tab['title'] . '"></a>';
1743					}
1744				}
1745			}
1746		}
1747	} else {
1748		if ($show_console_tab) {
1749			$tabs_left[] =
1750			array(
1751				'title' => __('Console'),
1752				'id'	=> 'tab-console',
1753				'url'   => $config['url_path'] . 'index.php',
1754			);
1755		}
1756
1757		if ($realm_allowed[7]) {
1758			if ($config['poller_id'] > 1 && $config['connection'] != 'online') {
1759				// Don't show the graphs tab when offline
1760			} else {
1761				$tabs_left[] =
1762					array(
1763						'title' => __('Graphs'),
1764						'id'	=> 'tab-graphs',
1765						'url'   => $config['url_path'] . 'graph_view.php',
1766					);
1767			}
1768		}
1769
1770		if ($realm_allowed[21] || $realm_allowed[22]) {
1771			if ($config['poller_id'] > 1) {
1772				// Don't show the reports tab on other pollers
1773			} else {
1774				$tabs_left[] =
1775					array(
1776						'title' => __('Reporting'),
1777						'id'	=> 'tab-reports',
1778						'url'   => $config['url_path'] . ($realm_allowed[22] ? 'reports_admin.php':'reports_user.php'),
1779					);
1780			}
1781		}
1782
1783		if ($realm_allowed[18] || $realm_allowed[19]) {
1784			$tabs_left[] =
1785				array(
1786					'title' => __('Logs'),
1787					'id'	=> 'tab-logs',
1788					'url'   => $config['url_path'] . ($realm_allowed[18] ? 'clog.php':'clog_user.php'),
1789				);
1790		}
1791
1792		// Get Plugin Text Out of Band
1793		ob_start();
1794		api_plugin_hook('top_graph_header_tabs');
1795
1796		$tab_text = trim(ob_get_clean());
1797		$tab_text = str_replace('<a', '', $tab_text);
1798		$tab_text = str_replace('</a>', '|', $tab_text);
1799		$tab_text = str_replace('<img', '', $tab_text);
1800		$tab_text = str_replace('<', '', $tab_text);
1801		$tab_text = str_replace('"', "'", $tab_text);
1802		$tab_text = str_replace('>', '', $tab_text);
1803		$elements = explode('|', $tab_text);
1804		$count    = 0;
1805
1806		foreach($elements as $p) {
1807			$p = trim($p);
1808
1809			if ($p == '') {
1810				continue;
1811			}
1812
1813			$altpos  = strpos($p, 'alt=');
1814			$hrefpos = strpos($p, 'href=');
1815			$idpos   = strpos($p, 'id=');
1816
1817			if ($altpos !== false) {
1818				$alt = substr($p, $altpos+4);
1819				$parts = explode("'", $alt);
1820				if ($parts[0] == '') {
1821					$alt = $parts[1];
1822				} else {
1823					$alt = $parts[0];
1824				}
1825			} else {
1826				$alt = __('Title');
1827			}
1828
1829			if ($hrefpos !== false) {
1830				$href = substr($p, $hrefpos+5);
1831				$parts = explode("'", $href);
1832				if ($parts[0] == '') {
1833					$href = $parts[1];
1834				} else {
1835					$href = $parts[0];
1836				}
1837			} else {
1838				$href = 'unknown';
1839			}
1840
1841			if ($idpos !== false) {
1842				$id = substr($p, $idpos+3);
1843				$parts = explode("'", $id);
1844				if ($parts[0] == '') {
1845					$id = $parts[1];
1846				} else {
1847					$id = $parts[0];
1848				}
1849			} else {
1850				$id = 'unknown' . $count;
1851				$count++;
1852			}
1853
1854			$tabs_left[] = array('title' => ucwords($alt), 'id' => 'tab-' . $id, 'url' => $href);
1855		}
1856
1857		if ($config['poller_id'] > 1 && $config['connection'] != 'online') {
1858			// Only show external links when online
1859		} else {
1860			$external_links = db_fetch_assoc('SELECT id, title
1861				FROM external_links
1862				WHERE style="TAB"
1863				AND enabled="on"
1864				ORDER BY sortorder');
1865
1866			if (cacti_sizeof($external_links)) {
1867				foreach($external_links as $tab) {
1868					if (is_realm_allowed($tab['id']+10000)) {
1869						$tabs_left[] =
1870							array(
1871								'title' => $tab['title'],
1872								'id'    => 'tab-link' . $tab['id'],
1873								'url'   => $config['url_path'] . 'link.php?id=' . $tab['id']
1874							);
1875					}
1876				}
1877			}
1878		}
1879
1880		$i = 0;
1881		$me_base = get_current_page();
1882		foreach($tabs_left as $tab) {
1883			$tab_base = basename($tab['url']);
1884
1885			if ($tab_base == 'graph_view.php' && ($me_base == 'graph_view.php' || $me_base == 'graph.php')) {
1886				$tabs_left[$i]['selected'] = true;
1887			} elseif (isset_request_var('id') && ($tab_base == 'link.php?id=' . get_nfilter_request_var('id')) && $me_base == 'link.php') {
1888				$tabs_left[$i]['selected'] = true;
1889			} elseif ($tab_base == 'index.php' && is_console_page($me_base)) {
1890				$tabs_left[$i]['selected'] = true;
1891			} elseif ($tab_base == $me_base) {
1892				$tabs_left[$i]['selected'] = true;
1893			}
1894
1895			$i++;
1896		}
1897
1898		$i = 0;
1899
1900		print "<div class='maintabs'><nav><ul role='tablist'>";
1901
1902		foreach($tabs_left as $tab) {
1903			if (isset($tab['id'])) {
1904				$id = $tab['id'];
1905			} else {
1906				$id = 'anchor' . $i;
1907				$i++;
1908			}
1909
1910			print "<li><a id='$id' role='tab' class='lefttab" . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . html_escape($tab['url']) . "'><span class='fa glyph_$id'></span><span class='text_$id'>" . html_escape($tab['title']) . "</span></a><a id='menu-$id' class='maintabs-submenu' href='#'><i class='fa fa-angle-down'></i></a></li>";
1911		}
1912
1913		print "<li class='ellipsis maintabs-submenu-ellipsis'><a id='menu-ellipsis' role='tab' aria-selected='false' class='submenu-ellipsis' href='#'><i class='fa fa-angle-down'></i></a></li>";
1914
1915		print '</ul></nav></div>';
1916	}
1917}
1918
1919function html_graph_tabs_right() {
1920	global $config, $tabs_right;
1921
1922	$theme = get_selected_theme();
1923
1924	if ($theme == 'classic') {
1925		if (is_view_allowed('show_tree')) {
1926			?><a class='righttab' id='treeview' href='<?php print html_escape($config['url_path'] . 'graph_view.php?action=tree');?>'><img src='<?php print $config['url_path']; ?>images/tab_mode_tree<?php
1927			if (isset_request_var('action') && get_nfilter_request_var('action') == 'tree') {
1928				print '_down';
1929			}?>.gif' title='<?php print __esc('Tree View');?>' alt=''></a><?php
1930		}?><?php
1931
1932		if (is_view_allowed('show_list')) {
1933			?><a class='righttab' id='listview' href='<?php print html_escape($config['url_path'] . 'graph_view.php?action=list');?>'><img src='<?php print $config['url_path']; ?>images/tab_mode_list<?php
1934			if (isset_request_var('action') && get_nfilter_request_var('action') == 'list') {
1935				print '_down';
1936			}?>.gif' title='<?php print __esc('List View');?>' alt=''></a><?php
1937		}?><?php
1938
1939		if (is_view_allowed('show_preview')) {
1940			?><a class='righttab' id='preview' href='<?php print html_escape($config['url_path'] . 'graph_view.php?action=preview');?>'><img src='<?php print $config['url_path']; ?>images/tab_mode_preview<?php
1941			if (isset_request_var('action') && get_nfilter_request_var('action') == 'preview') {
1942				print '_down';
1943			}?>.gif' title='<?php print __esc('Preview View');?>' alt=''></a><?php
1944		}?>&nbsp;<br>
1945		<?php
1946	} else {
1947		$tabs_right = array();
1948
1949		if (is_view_allowed('show_tree')) {
1950			$tabs_right[] = array(
1951				'title' => __('Tree View'),
1952				'image' => 'include/themes/' . $theme . '/images/tab_tree.gif',
1953				'id'    => 'tree',
1954				'url'   => 'graph_view.php?action=tree',
1955			);
1956		}
1957
1958		if (is_view_allowed('show_list')) {
1959			$tabs_right[] = array(
1960				'title' => __('List View'),
1961				'image' => 'include/themes/' . $theme . '/images/tab_list.gif',
1962				'id'    => 'list',
1963				'url'   => 'graph_view.php?action=list',
1964			);
1965		}
1966
1967		if (is_view_allowed('show_preview')) {
1968			$tabs_right[] = array(
1969				'title' => __('Preview'),
1970				'image' => 'include/themes/' . $theme . '/images/tab_preview.gif',
1971				'id'    => 'preview',
1972				'url'   => 'graph_view.php?action=preview',
1973			);
1974		}
1975
1976		$i = 0;
1977		foreach($tabs_right as $tab) {
1978			if ($tab['id'] == 'tree') {
1979				if (isset_request_var('action') && get_nfilter_request_var('action') == 'tree') {
1980					$tabs_right[$i]['selected'] = true;
1981				}
1982			} elseif ($tab['id'] == 'list') {
1983				if (isset_request_var('action') && get_nfilter_request_var('action') == 'list') {
1984					$tabs_right[$i]['selected'] = true;
1985				}
1986			} elseif ($tab['id'] == 'preview') {
1987				if (isset_request_var('action') && get_nfilter_request_var('action') == 'preview') {
1988					$tabs_right[$i]['selected'] = true;
1989				}
1990			} elseif (strstr(get_current_page(false), $tab['url'])) {
1991				$tabs_right[$i]['selected'] = true;
1992			}
1993
1994			$i++;
1995		}
1996
1997		print "<div class='tabs' style='float:right;'><nav><ul role='tablist'>";
1998		foreach($tabs_right as $tab) {
1999			switch($tab['id']) {
2000			case 'tree':
2001				if (isset($tab['image']) && $tab['image'] != '') {
2002					print "<li><a id='treeview' role='tab' title='" . html_escape($tab['title']) . "' class='righttab " . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . $tab['url'] . "'><img src='" . $config['url_path'] . $tab['image'] . "' alt='' style='vertical-align:bottom;'></a></li>";
2003				} else {
2004					print "<li><a role='tab' title='" . html_escape($tab['title']) . "' class='righttab " . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . $tab['url'] . "'>" . $tab['title'] . '</a></li>';
2005				}
2006				break;
2007			case 'list':
2008				if (isset($tab['image']) && $tab['image'] != '') {
2009					print "<li><a id='listview' role='tab' title='" . html_escape($tab['title']) . "' class='righttab " . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . $tab['url'] . "'><img src='" . $config['url_path'] . $tab['image'] . "' alt='' style='vertical-align:bottom;'></a></li>";
2010				} else {
2011					print "<li><a role='tab' title='" . html_escape($tab['title']) . "' class='righttab " . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . $tab['url'] . "'>" . $tab['title'] . '</a></li>';
2012				}
2013
2014				break;
2015			case 'preview':
2016				if (isset($tab['image']) && $tab['image'] != '') {
2017					print "<li><a role='tab' id='preview' title='" . html_escape($tab['title']) . "' class='righttab " . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . $tab['url'] . "'><img src='" . $config['url_path'] . $tab['image'] . "' alt='' style='vertical-align:bottom;'></a></li>";
2018				} else {
2019					print "<li><a role='tab' title='" . html_escape($tab['title']) . "' class='righttab " . (isset($tab['selected']) ? " selected' aria-selected='true'":"' aria-selected='false'") . " href='" . $tab['url'] . "'>" . $tab['title'] . '</a></li>';
2020				}
2021
2022				break;
2023			}
2024		}
2025		print '</ul></nav></div>';
2026	}
2027}
2028
2029function html_host_filter($host_id = '-1', $call_back = 'applyFilter', $sql_where = '', $noany = false, $nonone = false) {
2030	$theme = get_selected_theme();
2031
2032	if (strpos($call_back, '()') === false) {
2033		$call_back .= '()';
2034	}
2035
2036	if ($host_id == '-1' && isset_request_var('host_id')) {
2037		$host_id = get_filter_request_var('host_id');
2038	}
2039
2040	if ($theme == 'classic' || !read_config_option('autocomplete_enabled')) {
2041		?>
2042		<td>
2043			<?php print __('Device');?>
2044		</td>
2045		<td>
2046			<select id='host_id' name='host_id' onChange='<?php print $call_back;?>'>
2047				<?php if (!$noany) {?><option value='-1'<?php if ($host_id == '-1') {?> selected<?php }?>><?php print __('Any');?></option><?php }?>
2048				<?php if (!$nonone) {?><option value='0'<?php if ($host_id == '0') {?> selected<?php }?>><?php print __('None');?></option><?php }?>
2049				<?php
2050
2051				$devices = get_allowed_devices($sql_where);
2052
2053				if (cacti_sizeof($devices)) {
2054					foreach ($devices as $device) {
2055						print "<option value='" . $device['id'] . "'"; if ($host_id == $device['id']) { print ' selected'; } print '>' . html_escape(strip_domain($device['description'])) . '</option>';
2056					}
2057				}
2058				?>
2059			</select>
2060		</td>
2061		<?php
2062	} else {
2063		if ($host_id > 0) {
2064			$hostname = db_fetch_cell_prepared('SELECT description
2065				FROM host WHERE id = ?',
2066				array($host_id));
2067		} elseif ($host_id == 0) {
2068			$hostname = __('None');
2069		} else {
2070			$hostname = __('Any');
2071		}
2072
2073		?>
2074		<td>
2075			<?php print __('Device');?>
2076		</td>
2077		<td>
2078			<span id='host_wrapper' style='width:200px;' class='ui-selectmenu-button ui-selectmenu-button-closed ui-corner-all ui-corner-all ui-button ui-widget'>
2079				<span id='host_click' class='ui-selectmenu-icon ui-icon ui-icon-triangle-1-s'></span>
2080				<span class='ui-select-text'>
2081					<input type='text' size='28' id='host' value='<?php print html_escape($hostname);?>'>
2082				</span>
2083			</span>
2084			<input type='hidden' id='host_id' name='host_id' value='<?php print $host_id;?>'>
2085			<input type='hidden' id='call_back' value='<?php print $call_back;?>'>
2086		</td>
2087	<?php
2088	}
2089}
2090
2091function html_site_filter($site_id = '-1', $call_back = 'applyFilter', $sql_where = '', $noany = false, $nonone = false) {
2092	$theme = get_selected_theme();
2093
2094	if (strpos($call_back, '()') === false) {
2095		$call_back .= '()';
2096	}
2097
2098	if ($site_id == '-1' && isset_request_var('site_id')) {
2099		$site_id = get_filter_request_var('site_id');
2100	}
2101
2102	?>
2103	<td>
2104		<?php print __('Site');?>
2105	</td>
2106	<td>
2107		<select id='site_id' onChange='<?php print $call_back;?>'>
2108			<?php if (!$noany) {?><option value='-1'<?php if ($site_id == '-1') {?> selected<?php }?>><?php print __('Any');?></option><?php }?>
2109			<?php if (!$nonone) {?><option value='0'<?php if ($site_id == '0') {?> selected<?php }?>><?php print __('None');?></option><?php }?>
2110			<?php
2111
2112			$sites = get_allowed_sites($sql_where);
2113
2114			if (cacti_sizeof($sites)) {
2115				foreach ($sites as $site) {
2116					print "<option value='" . $site['id'] . "'"; if ($site_id == $site['id']) { print ' selected'; } print '>' . html_escape($site['name']) . '</option>';
2117				}
2118			}
2119			?>
2120		</select>
2121	</td>
2122	<?php
2123}
2124
2125function html_spikekill_actions() {
2126	switch(get_nfilter_request_var('action')) {
2127		case 'spikemenu':
2128			html_spikekill_menu(get_filter_request_var('local_graph_id'));
2129
2130			break;
2131		case 'spikesave':
2132			switch(get_nfilter_request_var('setting')) {
2133				case 'ravgnan':
2134					$id = get_nfilter_request_var('id');
2135					switch($id) {
2136						case 'avg':
2137						case 'last':
2138						case 'nan':
2139							set_user_setting('spikekill_avgnan', $id);
2140							break;
2141					}
2142
2143					break;
2144				case 'rstddev':
2145					set_user_setting('spikekill_deviations', get_filter_request_var('id'));
2146					break;
2147				case 'rvarout':
2148					set_user_setting('spikekill_outliers', get_filter_request_var('id'));
2149					break;
2150				case 'rvarpct':
2151					set_user_setting('spikekill_percent', get_filter_request_var('id'));
2152					break;
2153				case 'rkills':
2154					set_user_setting('spikekill_number', get_filter_request_var('id'));
2155					break;
2156			}
2157
2158			break;
2159	}
2160}
2161
2162function html_spikekill_setting($name) {
2163	return read_user_setting($name, read_config_option($name), true);
2164}
2165
2166function html_spikekill_menu_item($text, $icon = '', $class = '', $id = '', $data_graph = '', $subitem = '') {
2167	$output = '<li ';
2168
2169	if (!empty($id)) {
2170		$output .= "id='$id' ";
2171	}
2172
2173	if (!empty($data_graph)) {
2174		$output .= "data-graph='$data_graph' ";
2175	}
2176
2177	$output .= 'class=\'' . (empty($class)?'': " $class") . '\'>';
2178	$output .= '<span class=\'spikeKillMenuItem\'>';
2179	if (!empty($icon)) {
2180		$output .= "<i class='$icon'></i>";
2181	}
2182
2183	$output .= "$text</span>";
2184
2185	if (!empty($subitem)) {
2186		$output .= "<ul>$subitem</ul>";
2187	}
2188
2189	$output .= '</li>';
2190	return $output;
2191}
2192
2193function html_spikekill_menu($local_graph_id) {
2194	global $settings;
2195	$ravgnan1 = html_spikekill_menu_item(__('Average'), html_spikekill_setting('spikekill_avgnan') == 'avg' ? 'fa fa-check':'fa', 'skmethod', 'method_avg');
2196	$ravgnan2 = html_spikekill_menu_item(__('NaN\'s'), html_spikekill_setting('spikekill_avgnan') == 'nan' ? 'fa fa-check':'fa', 'skmethod', 'method_nan');
2197	$ravgnan3 = html_spikekill_menu_item(__('Last Known Good'), html_spikekill_setting('spikekill_avgnan') == 'last' ? 'fa fa-check':'fa', 'skmethod', 'method_last');
2198
2199	$ravgnan = html_spikekill_menu_item(__('Replacement Method'), '', '', '', '', $ravgnan1 . $ravgnan2 . $ravgnan3);
2200
2201	$rstddev = '';
2202	foreach ($settings['spikes']['spikekill_deviations']['array'] as $key => $value) {
2203		$rstddev .= html_spikekill_menu_item($value, html_spikekill_setting('spikekill_deviations') == $key ? 'fa fa-check':'fa', 'skstddev', 'stddev_' . $key);
2204	}
2205	$rstddev  = html_spikekill_menu_item(__('Standard Deviations'), '', '', '', '', $rstddev);
2206
2207	$rvarpct = '';
2208	foreach ($settings['spikes']['spikekill_percent']['array'] as $key => $value) {
2209		$rvarpct .= html_spikekill_menu_item($value, html_spikekill_setting('spikekill_percent') == $key ? 'fa fa-check':'fa', 'skvarpct', 'varpct_' . $key);
2210	}
2211	$rvarpct = html_spikekill_menu_item(__('Variance Percentage'), '', '', '', '', $rvarpct);
2212
2213	$rvarout  = '';
2214	foreach ($settings['spikes']['spikekill_outliers']['array'] as $key => $value) {
2215		$rvarout .= html_spikekill_menu_item($value, html_spikekill_setting('spikekill_outliers') == $key ? 'fa fa-check':'fa', 'skvarout', 'varout_' . $key);
2216	}
2217	$rvarout  = html_spikekill_menu_item(__('Variance Outliers'), '', '', '', '', $rvarout);
2218
2219	$rkills  = '';
2220	foreach ($settings['spikes']['spikekill_number']['array'] as $key => $value) {
2221		$rkills .= html_spikekill_menu_item($value,html_spikekill_setting('spikekill_number') == $key ? 'fa fa-check':'fa', 'skkills', 'kills_' . $key);
2222	}
2223	$rkills  = html_spikekill_menu_item(__('Kills Per RRA'), '', '', '', '', $rkills);
2224
2225	?>
2226	<div class='spikekillParent' style='display:none;z-index:20;position:absolute;text-align:left;white-space:nowrap;padding-right:2px;'>
2227	<ul class='spikekillMenu' style='font-size:1em;'>
2228	<?php
2229	print html_spikekill_menu_item(__('Remove StdDev'), 'deviceUp fa fa-life-ring', 'rstddev', '',  $local_graph_id);
2230	print html_spikekill_menu_item(__('Remove Variance'), 'deviceRecovering fa fa-life-ring', 'rvariance', '',  $local_graph_id);
2231	print html_spikekill_menu_item(__('Gap Fill Range'), 'deviceUnknown fa fa-life-ring', 'routlier', '',  $local_graph_id);
2232	print html_spikekill_menu_item(__('Float Range'), 'deviceDown fa fa-life-ring', 'rrangefill', '',  $local_graph_id);
2233
2234	print html_spikekill_menu_item(__('Dry Run StdDev'), 'deviceUp fa fa-check', 'dstddev', '',  $local_graph_id);
2235	print html_spikekill_menu_item(__('Dry Run Variance'), 'deviceRecovering fa fa-check', 'dvariance', '',  $local_graph_id);
2236	print html_spikekill_menu_item(__('Dry Run Gap Fill Range'), 'deviceUnknown fa fa-check', 'doutlier', '',  $local_graph_id);
2237	print html_spikekill_menu_item(__('Dry Run Float Range'), 'deviceDown fa fa-check', 'drangefill', '',  $local_graph_id);
2238
2239	print html_spikekill_menu_item(__('Settings'), 'fa fa-cog', '', '', '', $ravgnan . $rstddev . $rvarpct . $rvarout . $rkills);
2240}
2241
2242function html_spikekill_js() {
2243	?>
2244	<script type='text/javascript'>
2245	spikeKillOpen = false;
2246	$(function() {
2247		$(document).click(function() {
2248			if (spikeKillOpen) {
2249				$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2250				spikeKillOpen = false;
2251			}
2252		});
2253
2254		$('span.spikekill').children().contextmenu(function() {
2255			return false;
2256		});
2257
2258		$('span.spikekill').unbind().click(function() {
2259			if (spikeKillOpen == false) {
2260				local_graph_id = $(this).attr('data-graph');
2261
2262				$.get('?action=spikemenu&local_graph_id='+local_graph_id)
2263					.done(function(data) {
2264						$('#sk'+local_graph_id).after(data);
2265
2266						menuAnchor = $('#sk'+local_graph_id).offset().left;
2267						pageWidth  = $(document).width();
2268
2269						if (pageWidth - menuAnchor < 180) {
2270							$('.spikekillMenu').css({ position: 'absolute', top: 0, left: -180 });
2271						}
2272
2273						$('.spikekillMenu').menu({
2274							select: function(event, ui) {
2275								$(this).menu('focus', event, ui.item);
2276							},
2277							delay: 1000
2278						});
2279
2280						$('.spikekillParent').show();
2281
2282						spikeKillActions();
2283
2284						spikeKillOpen = true;
2285					})
2286					.fail(function(data) {
2287						getPresentHTTPError(data);
2288					});
2289
2290			} else {
2291				spikeKillOpen = false;
2292				$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2293			}
2294		});
2295	});
2296
2297	function spikeKillActions() {
2298		$('.rstddev').unbind().click(function() {
2299			removeSpikesStdDev($(this).attr('data-graph'));
2300			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2301		});
2302
2303		$('.dstddev').unbind().click(function() {
2304			dryRunStdDev($(this).attr('data-graph'));
2305			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2306		});
2307
2308		$('.rvariance').unbind().click(function() {
2309			removeSpikesVariance($(this).attr('data-graph'));
2310			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2311		});
2312
2313		$('.dvariance').unbind().click(function() {
2314			dryRunVariance($(this).attr('data-graph'));
2315			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2316		});
2317
2318		$('.routlier').unbind().click(function() {
2319			removeSpikesInRange($(this).attr('data-graph'));
2320			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2321		});
2322
2323		$('.doutlier').unbind().click(function() {
2324			dryRunSpikesInRange($(this).attr('data-graph'));
2325			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2326		});
2327
2328		$('.rrangefill').unbind().click(function() {
2329			removeRangeFill($(this).attr('data-graph'));
2330			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2331		});
2332
2333		$('.drangefill').unbind().click(function() {
2334			dryRunRangeFill($(this).attr('data-graph'));
2335			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2336		});
2337
2338		$('.skmethod').unbind().click(function() {
2339			$('.skmethod').find('i').removeClass('fa fa-check');
2340			$(this).find('i:first').addClass('fa fa-check');
2341			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2342
2343			strURL = '?action=spikesave&setting=ravgnan&id='+$(this).attr('id').replace('method_','');
2344			$.get(strURL)
2345				.fail(function(data) {
2346					getPresentHTTPError(data);
2347				});
2348		});
2349
2350		$('.skkills').unbind().click(function() {
2351			$('.skkills').find('i').removeClass('fa fa-check');
2352			$(this).find('i:first').addClass('fa fa-check');
2353			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2354
2355			strURL = '?action=spikesave&setting=rkills&id='+$(this).attr('id').replace('kills_','');
2356			$.get(strURL)
2357				.fail(function(data) {
2358					getPresentHTTPError(data);
2359				});
2360		});
2361
2362		$('.skstddev').unbind().click(function() {
2363			$('.skstddev').find('i').removeClass('fa fa-check');
2364			$(this).find('i:first').addClass('fa fa-check');
2365			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2366
2367			strURL = '?action=spikesave&setting=rstddev&id='+$(this).attr('id').replace('stddev_','');
2368			$.get(strURL)
2369				.fail(function(data) {
2370					getPresentHTTPError(data);
2371				});
2372		});
2373
2374		$('.skvarpct').unbind().click(function() {
2375			$('.skvarpct').find('i').removeClass('fa fa-check');
2376			$(this).find('i:first').addClass('fa fa-check');
2377			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2378
2379			strURL = '?action=spikesave&setting=rvarpct&id='+$(this).attr('id').replace('varpct_','');
2380			$.get(strURL)
2381				.fail(function(data) {
2382					getPresentHTTPError(data);
2383				});
2384		});
2385
2386		$('.skvarout').unbind().click(function() {
2387			$('.skvarout').find('i').removeClass('fa fa-check');
2388			$(this).find('i:first').addClass('fa fa-check');
2389			$(this).find('.spikekillMenu').menu('destroy').parent().remove();
2390
2391			strURL = '?action=spikesave&setting=rvarout&id='+$(this).attr('id').replace('varout_','');
2392			$.get(strURL)
2393				.fail(function(data) {
2394					getPresentHTTPError(data);
2395				});
2396		});
2397	}
2398	</script>
2399	<?php
2400}
2401
2402/* html_common_header - prints a common set of header, css and javascript links
2403   @arg title - the title of the page to place in the browser
2404   @arg selectedTheme - optionally sets a specific theme over the current one
2405*/
2406function html_common_header($title, $selectedTheme = '') {
2407	global $config, $path2calendar, $path2timepicker, $path2colorpicker;
2408
2409	if ($selectedTheme == '') {
2410		$selectedTheme = get_selected_theme();
2411	}
2412
2413	if ($selectedTheme == 'classic') {
2414		print "<meta content='width=device-width, initial-scale=0.5, minimum-scale=0.2, maximum-scale=5' name='viewport'>" . PHP_EOL;
2415	} else {
2416		print "<meta content='width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5' name='viewport'>" . PHP_EOL;
2417	}
2418
2419	$script_policy = read_config_option('content_security_policy_script');
2420	if ($script_policy == 'unsafe-eval') {
2421		$script_policy = "'$script_policy'";
2422	} else {
2423		$script_policy = '';
2424	}
2425	$alternates = html_escape(read_config_option('content_security_alternate_sources'));
2426
2427	?>
2428	<meta http-equiv='X-UA-Compatible' content='IE=Edge,chrome=1'>
2429	<meta name='apple-mobile-web-app-capable' content='yes'>
2430	<meta name='description' content='Monitoring tool of the Internet'>
2431	<meta name='mobile-web-app-capable' content='yes'>
2432	<meta name="theme-color" content="#161616"/>
2433	<meta http-equiv="Content-Security-Policy" content="default-src *; img-src 'self' <?php print $alternates;?> data: blob:; style-src 'self' 'unsafe-inline' <?php print $alternates;?>; script-src 'self' <?php print html_escape($script_policy);?> 'unsafe-inline' <?php print $alternates;?>; worker-src 'self' <?php print $alternates;?>;">
2434	<meta name='robots' content='noindex,nofollow'>
2435	<title><?php print $title; ?></title>
2436	<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>
2437	<script type='text/javascript'>
2438		var theme='<?php print $selectedTheme;?>';
2439		var hScroll=<?php print read_user_setting('enable_hscroll', '') == 'on' ? 'true':'false';?>;
2440		var userSettings=<?php print is_view_allowed('graph_settings') ? 'true':'false';?>;
2441		var tableConstraints='<?php print __('Allow or limit the table columns to extend beyond the current windows limits.');?>';
2442		var searchFilter='<?php print __esc('Enter a search term');?>';
2443		var searchRFilter='<?php print __esc('Enter a regular expression');?>';
2444		var noFileSelected='<?php print __esc('No file selected');?>';
2445		var timeGraphView='<?php print __esc('Time Graph View');?>';
2446		var filterSettingsSaved='<?php print __esc('Filter Settings Saved');?>';
2447		var spikeKillResuls='<?php print __esc('SpikeKill Results');?>';
2448		var utilityView='<?php print __esc('Utility View');?>';
2449		var realtimeClickOn='<?php print __esc('Click to view just this Graph in Realtime');?>';
2450		var realtimeClickOff='<?php print __esc('Click again to take this Graph out of Realtime');?>';
2451		var treeView='<?php print __esc('Tree View');?>';
2452		var listView='<?php print __esc('List View');?>';
2453		var previewView='<?php print __esc('Preview View');?>';
2454		var editProfile='<?php print __esc('Edit Profile');?>';
2455		var changePassword='<?php print __esc('Change Password');?>';
2456		var logout='<?php print __esc('Logout');?>';
2457		var standardGraphicalUserInterface='<?php print __esc('Standard Mode');?>';
2458		var compactGraphicalUserInterface='<?php print __esc('Compact Mode');?>';
2459		var darkColorMode='<?php print __esc('Dark Color Mode');?>';
2460		var lightColorMode='<?php print __esc('Light Color Mode');?>';
2461		var usePreferredColorTheme='<?php print __esc('Use System Color');?>';
2462		var ignorePreferredColorTheme='<?php print __esc('Ignore System Color');?>';
2463		var help='<?php print __esc('Help');?>';
2464		var cactiHome='<?php print __esc('Cacti Home');?>';
2465		var cactiProjectPage='<?php print __esc('Cacti Project Page');?>';
2466		var cactiCommunityForum='<?php print __esc('User Community');?>';
2467		var cactiDocumentation='<?php print __esc('Documentation');?>';
2468		var reportABug='<?php print __esc('Report a bug');?>';
2469		var aboutCacti='<?php print __esc('About Cacti');?>';
2470		var spikeKillResults='<?php print __esc('SpikeKill Results');?>';
2471		var showHideFilter='<?php print __esc('Click to Show/Hide Filter');?>';
2472		var clearFilterTitle='<?php print __esc('Clear Current Filter');?>';
2473		var clipboard='<?php print __esc('Clipboard');?>';
2474		var clipboardID='<?php print __esc('Clipboard ID');?>';
2475		var clipboardNotAvailable='<?php print __esc('Copy operation is unavailable at this time');?>';
2476		var clipboardCopyFailed='<?php print __esc('Failed to find data to copy!');?>';
2477		var clipboardUpdated='<?php print __esc('Clipboard has been updated');?>';
2478		var clipboardNotUpdated='<?php print __esc('Sorry, your clipboard could not be updated at this time');?>';
2479		var defaultSNMPSecurityLevel='<?php print read_config_option('snmp_security_level');?>';
2480		var defaultSNMPAuthProtocol='<?php print read_config_option('snmp_auth_protocol');?>';
2481		var defaultSNMPPrivProtocol='<?php print read_config_option('snmp_priv_protocol');?>';
2482		var passwordPass='<?php print __esc('Passphrase length meets 8 character minimum');?>';
2483		var passwordTooShort='<?php print __esc('Passphrase too short');?>';
2484		var passwordMatchTooShort='<?php print __esc('Passphrase matches but too short');?>';
2485		var passwordNotMatchTooShort='<?php print __esc('Passphrase too short and not matching');?>';
2486		var passwordMatch='<?php print __esc('Passphrases match');?>';
2487		var passwordNotMatch='<?php print __esc('Passphrases do not match');?>';
2488		var errorOnPage='<?php print __esc('Sorry, we could not process your last action.');?>';
2489		var errorNumberPrefix='<?php print __esc('Error:');?>';
2490		var errorReasonPrefix='<?php print __esc('Reason:');?>';
2491		var errorReasonTitle='<?php print __esc('Action failed');?>';
2492		var testSuccessful='<?php print __esc('Connection Successful');?>';
2493		var testFailed='<?php print __esc('Connection Failed');?>';
2494		var errorReasonUnexpected='<?php print __esc('The response to the last action was unexpected.');?>';
2495		var mixedReasonTitle='<?php print __esc('Some Actions failed');?>';
2496		var mixedOnPage='<?php print __esc('Note, we could not process all your actions.  Details are below.');?>';
2497		var sessionMessageTitle='<?php print __esc('Operation successful');?>';
2498		var sessionMessageSave='<?php print __esc('The Operation was successful.  Details are below.');?>';
2499		var sessionMessageOk='<?php print __esc('Ok');?>';
2500		var sessionMessagePause='<?php print __esc('Pause');?>';
2501		var sessionMessageContinue='<?php print __esc('Continue');?>';
2502		var sessionMessageCancel='<?php print __esc('Cancel');?>';
2503		var zoom_i18n_zoom_in='<?php print __esc('Zoom In');?>';
2504		var zoom_i18n_zoom_out='<?php print __esc('Zoom Out');?>';
2505		var zoom_i18n_zoom_out_factor='<?php print __esc('Zoom Out Factor');?>';
2506		var zoom_i18n_timestamps='<?php print __esc('Timestamps');?>';
2507		var zoom_i18n_zoom_2='<?php print __esc('2x');?>';
2508		var zoom_i18n_zoom_4='<?php print __esc('4x');?>';
2509		var zoom_i18n_zoom_8='<?php print __esc('8x');?>';
2510		var zoom_i18n_zoom_16='<?php print __esc('16x');?>';
2511		var zoom_i18n_zoom_32='<?php print __esc('32x');?>';
2512		var zoom_i18n_zoom_out_positioning='<?php print __esc('Zoom Out Positioning');?>';
2513		var zoom_i18n_mode='<?php print __esc('Zoom Mode');?>';
2514		var zoom_i18n_graph='<?php print __esc('Graph');?>';
2515		var zoom_i18n_quick='<?php print __esc('Quick');?>';
2516		var zoom_i18n_advanced='<?php print __esc('Advanced');?>';
2517		var zoom_i18n_newTab='<?php print __esc('Open in new tab');?>';
2518		var zoom_i18n_save_graph='<?php print __esc('Save graph');?>';
2519		var zoom_i18n_copy_graph='<?php print __esc('Copy graph');?>';
2520		var zoom_i18n_copy_graph_link='<?php print __esc('Copy graph link');?>';
2521		var zoom_i18n_on='<?php print __esc('Always On');?>';
2522		var zoom_i18n_auto='<?php print __esc('Auto');?>';
2523		var zoom_i18n_off='<?php print __esc('Always Off');?>';
2524		var zoom_i18n_begin='<?php print __esc('Begin with');?>';
2525		var zoom_i18n_center='<?php print __esc('Center');?>';
2526		var zoom_i18n_end='<?php print __esc('End with');?>';
2527		var zoom_i18n_disabled='<?php print __esc('Disabled');?>';
2528		var zoom_i18n_close='<?php print __esc('Close');?>';
2529		var zoom_i18n_settings='<?php print __esc('Settings');?>';
2530		var zoom_i18n_3rd_button='<?php print __esc('3rd Mouse Button');?>';
2531	</script>
2532	<link href='<?php print $config['url_path']; ?>include/themes/<?php print $selectedTheme;?>/images/favicon.ico' rel='shortcut icon'>
2533	<link href='<?php print $config['url_path']; ?>include/themes/<?php print $selectedTheme;?>/images/cacti_logo.gif' rel='icon' sizes='96x96'>
2534	<?php
2535	print get_md5_include_css('include/themes/' . $selectedTheme .'/jquery.zoom.css');
2536	print get_md5_include_css('include/themes/' . $selectedTheme .'/jquery-ui.css');
2537	print get_md5_include_css('include/themes/' . $selectedTheme .'/default/style.css');
2538	print get_md5_include_css('include/themes/' . $selectedTheme .'/jquery.multiselect.css');
2539	print get_md5_include_css('include/themes/' . $selectedTheme .'/jquery.multiselect.filter.css');
2540	print get_md5_include_css('include/themes/' . $selectedTheme .'/jquery.timepicker.css');
2541	print get_md5_include_css('include/themes/' . $selectedTheme .'/jquery.colorpicker.css');
2542	print get_md5_include_css('include/themes/' . $selectedTheme .'/billboard.css');
2543	print get_md5_include_css('include/themes/' . $selectedTheme .'/pace.css');
2544	print get_md5_include_css('include/fa/css/all.css');
2545	print get_md5_include_css('include/vendor/flag-icon-css/css/flag-icon.css');
2546	print get_md5_include_css('include/themes/' . $selectedTheme .'/main.css');
2547	print get_md5_include_js('include/js/screenfull.js', true);
2548	print get_md5_include_js('include/js/jquery.js');
2549	print get_md5_include_js('include/js/jquery-ui.js');
2550	print get_md5_include_js('include/js/jquery.ui.touch.punch.js', true);
2551	print get_md5_include_js('include/js/jquery.cookie.js');
2552	print get_md5_include_js('include/js/js.storage.js');
2553	print get_md5_include_js('include/js/jstree.js');
2554	print get_md5_include_js('include/js/jquery.hotkeys.js', true);
2555	print get_md5_include_js('include/js/jquery.tablednd.js', true);
2556	print get_md5_include_js('include/js/jquery.zoom.js', true);
2557	print get_md5_include_js('include/js/jquery.multiselect.js');
2558	print get_md5_include_js('include/js/jquery.multiselect.filter.js');
2559	print get_md5_include_js('include/js/jquery.timepicker.js');
2560	print get_md5_include_js('include/js/jquery.colorpicker.js', true);
2561	print get_md5_include_js('include/js/jquery.tablesorter.js');
2562	print get_md5_include_js('include/js/jquery.tablesorter.widgets.js', true);
2563	print get_md5_include_js('include/js/jquery.tablesorter.pager.js', true);
2564	print get_md5_include_js('include/js/jquery.sparkline.js', true);
2565	print get_md5_include_js('include/js/Chart.js', true);
2566	print get_md5_include_js('include/js/dygraph-combined.js', true);
2567	print get_md5_include_js('include/js/d3.js');
2568	print get_md5_include_js('include/js/billboard.js');
2569	print get_md5_include_js('include/layout.js');
2570	print get_md5_include_js('include/js/pace.js');
2571	print get_md5_include_js('include/realtime.js', true);
2572	print get_md5_include_js('include/themes/' . $selectedTheme .'/main.js');
2573
2574	if (isset($path2calendar) && file_exists($path2calendar)) {
2575		print get_md5_include_js($path2calendar);
2576	}
2577
2578	if (isset($path2timepicker) && file_exists($path2timepicker)) {
2579		print get_md5_include_js($path2timepicker);
2580	}
2581
2582	if (isset($path2colorpicker) && file_exists($path2colorpicker)) {
2583		print get_md5_include_js($path2colorpicker);
2584	}
2585
2586	if (file_exists('include/themes/custom.css')) {
2587		print get_md5_include_css('include/themes/custom.css');
2588	}
2589	api_plugin_hook('page_head');
2590}
2591
2592function html_help_page($page) {
2593	global $config;
2594
2595	$help = array(
2596		'aggregates.php'              => 'Aggregates.html',
2597		'aggregate_templates.php'     => 'Aggregate-Templates.html',
2598		'automation_networks.php'     => 'Automation-Networks.php',
2599		'cdef.php'                    => 'CDEFs.html',
2600		'color_templates.php'         => 'Color-Templates.html',
2601		'color.php'                   => 'Colors.html',
2602		'pollers.php'                 => 'Data-Collectors.html',
2603		'data_debug.php'              => 'Data-Debug.html',
2604		'data_input.php'              => 'Data-Input-Methods.html',
2605		'data_source_profiles.php'    => 'Data-Profiles.html',
2606		'data_queries.php'            => 'Data-Queries.html',
2607		'data_templates.php'          => 'Data-Source-Templates.html',
2608		'data_sources.php'            => 'Data-Sources.html',
2609		'host.php'                    => 'Devices.html',
2610		'automation_templates.php'    => 'Device-Rules.html',
2611		'host_templates.php'          => 'Device-Templates.html',
2612		'automation_devices.php'      => 'Discovered-Devices.html',
2613		'templates_export.php'        => 'Export-Template.html',
2614		'links.php'                   => 'External-Links.html',
2615		'gprint_presets.php'          => 'GPRINTs.html',
2616		'graphs_new.php'              => 'Graph-a-Single-SNMP-OID.html',
2617		'graph_view.php'              => 'Graph-Overview.html',
2618		'automation_graph_rules.php'  => 'Graph-Rules.html',
2619		'graph_templates.php'         => 'Graph-Templates.html',
2620		'graph_templates_items.php'   => 'Graph-Templates.html',
2621		'graph_templates_inputs.php'  => 'Graph-Templates.html',
2622		'graphs.php'                  => 'Graphs.html',
2623		'templates_import.php'        => 'Import-Template.html',
2624		'plugins.php'                 => 'Plugins.html',
2625		'automation_snmp.php'         => 'SNMP-Options.html',
2626		'settings.php:authentication' => 'Settings-Auth.html',
2627		'settings.php:data'           => 'Settings-Data.html',
2628		'settings.php:snmp'           => 'Settings-Device-Defaults.html',
2629		'settings.php:general'        => 'Settings-General.html',
2630		'settings.php:mail'           => 'Settings-Mail-Reporting-DNS.html',
2631		'settings.php:path'           => 'Settings-Paths.html',
2632		'settings.php:boost'          => 'Settings-Performance.html',
2633		'settings.php:poller'         => 'Settings-Poller.html',
2634		'settings.php:spikes'         => 'Settings-Spikes.html',
2635		'settings.php:visual'         => 'Settings-Visual.html',
2636		'sites.php'                   => 'Sites.html',
2637		'automation_tree_rules.php'   => 'Tree-Rules.html',
2638		'tree.php'                    => 'Trees.html',
2639		'user_domains.php'            => 'User-Domains.html',
2640		'user_group_admin.php'        => 'User-Group-Management.html',
2641		'user_admin.php'              => 'User-Management.html',
2642		'vdef.php'                    => 'VDEFs.html',
2643	);
2644
2645	$help = api_plugin_hook_function('help_page', $help);
2646
2647	if (isset($help[$page])) {
2648		if (file_exists($config['base_path'] . '/docs/' . $help[$page])) {
2649			return $config['url_path'] . 'docs/' . $help[$page];
2650		}
2651	}
2652
2653	return false;
2654}
2655