Project

General

Profile

Download (20.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pkg.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions are met:
11
 *
12
 * 1. Redistributions of source code must retain the above copyright notice,
13
 *    this list of conditions and the following disclaimer.
14
 *
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in
17
 *    the documentation and/or other materials provided with the
18
 *    distribution.
19
 *
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgment:
22
 *    "This product includes software developed by the pfSense Project
23
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
24
 *
25
 * 4. The names "pfSense" and "pfSense Project" must not be used to
26
 *    endorse or promote products derived from this software without
27
 *    prior written permission. For written permission, please contact
28
 *    coreteam@pfsense.org.
29
 *
30
 * 5. Products derived from this software may not be called "pfSense"
31
 *    nor may "pfSense" appear in their names without prior written
32
 *    permission of the Electric Sheep Fencing, LLC.
33
 *
34
 * 6. Redistributions of any form whatsoever must retain the following
35
 *    acknowledgment:
36
 *
37
 * "This product includes software developed by the pfSense Project
38
 * for use in the pfSense software distribution (http://www.pfsense.org/).
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
 * OF THE POSSIBILITY OF SUCH DAMAGE.
52
 */
53

    
54
##|+PRIV
55
##|*IDENT=page-package-settings
56
##|*NAME=Package: Settings
57
##|*DESCR=Allow access to the 'Package: Settings' page.
58
##|*MATCH=pkg.php*
59
##|-PRIV
60

    
61
require_once("guiconfig.inc");
62
require_once("pkg-utils.inc");
63

    
64
function domTT_title($title_msg) {
65
	print "onmouseout=\"this.style.color = ''; domTT_mouseout(this, event);\" onmouseover=\"domTT_activate(this, event, 'content', '".gettext($title_msg)."', 'trail', true, 'delay', 0, 'fade', 'both', 'fadeMax', 93, 'styleClass', 'niceTitle');\"";
66
}
67

    
68
$xml = $_REQUEST['xml'];
69

    
70
if ($xml == "") {
71
	$pgtitle = array(gettext("Package"), gettext("Editor"));
72
	$pglinks = array("", "@self");
73
	include("head.inc");
74
	print_info_box(gettext("No valid package defined."), 'danger', false);
75
	include("foot.inc");
76
	exit;
77
} else {
78
	$pkg_xml_prefix = "/usr/local/pkg/";
79
	$pkg_full_path = "{$pkg_xml_prefix}/{$xml}";
80
	$pkg_realpath = realpath($pkg_full_path);
81
	if (empty($pkg_realpath)) {
82
		$path_error = sprintf(gettext("Package path %s not found."), htmlspecialchars($pkg_full_path));
83
	} else if (substr_compare($pkg_realpath, $pkg_xml_prefix, 0, strlen($pkg_xml_prefix))) {
84
		$path_error = sprintf(gettext("Invalid path %s specified."), htmlspecialchars($pkg_full_path));
85
	}
86

    
87
	if (!empty($path_error)) {
88
		include("head.inc");
89
		print_info_box($path_error . "<br />" . gettext("Try reinstalling the package."), 'danger', false);
90
		include("foot.inc");
91
		die;
92
	}
93

    
94
	if (file_exists($pkg_full_path)) {
95
		$pkg = parse_xml_config_pkg($pkg_full_path, "packagegui");
96
	} else {
97
		include("head.inc");
98
		print_info_box(sprintf(gettext("File not found %s."), htmlspecialchars($xml)), 'danger', false);
99
		include("foot.inc");
100
		exit;
101
	}
102
}
103

    
104
if ($pkg['donotsave'] != "") {
105
	header("Location: pkg_edit.php?xml=" . $xml);
106
	exit;
107
}
108

    
109
if ($pkg['include_file'] != "") {
110
	require_once($pkg['include_file']);
111
}
112

    
113
if ($_REQUEST['startdisplayingat']) {
114
	$startdisplayingat = $_REQUEST['startdisplayingat'];
115
}
116

    
117
if ($_REQUEST['display_maximum_rows']) {
118
	if ($_REQUEST['display_maximum_rows']) {
119
		$display_maximum_rows = $_REQUEST['display_maximum_rows'];
120
	}
121
}
122

    
123
$evaledvar = $config['installedpackages'][xml_safe_fieldname($pkg['name'])]['config'];
124

    
125
if ($_GET['act'] == "update") {
126

    
127
	if (is_array($config['installedpackages'][$pkg['name']]) && $pkg['name'] != "" && $_REQUEST['ids'] !="") {
128
		#get current values
129
		$current_values=$config['installedpackages'][$pkg['name']]['config'];
130
		#get updated ids
131
		parse_str($_REQUEST['ids'], $update_list);
132
		#sort ids to know what to change
133
		#useful to do not lose data when using sorting and paging
134
		$sort_list=$update_list['ids'];
135
		sort($sort_list);
136
		#apply updates
137
		foreach ($update_list['ids'] as $key=> $value) {
138
			$config['installedpackages'][$pkg['name']]['config'][$sort_list[$key]]=$current_values[$update_list['ids'][$key]];
139
		}
140
		#save current config
141
		write_config();
142
		#sync package
143
		eval ("{$pkg['custom_php_resync_config_command']}");
144
	}
145
	#function called via jquery, no need to continue after save changes.
146
	exit;
147
}
148
if ($_GET['act'] == "del") {
149
	// loop through our fieldnames and automatically setup the fieldnames
150
	// in the environment.	ie: a fieldname of username with a value of
151
	// testuser would automatically eval $username = "testuser";
152
	foreach ($evaledvar as $ip) {
153
		if ($pkg['adddeleteeditpagefields']['columnitem']) {
154
			foreach ($pkg['adddeleteeditpagefields']['columnitem'] as $column) {
155
				${xml_safe_fieldname($column['fielddescr'])} = $ip[xml_safe_fieldname($column['fieldname'])];
156
			}
157
		}
158
	}
159

    
160
	$a_pkg = &$config['installedpackages'][xml_safe_fieldname($pkg['name'])]['config'];
161

    
162
	if ($a_pkg[$_GET['id']]) {
163
		unset($a_pkg[$_GET['id']]);
164
		write_config();
165
		if ($pkg['custom_delete_php_command'] != "") {
166
			if ($pkg['custom_php_command_before_form'] != "") {
167
				eval($pkg['custom_php_command_before_form']);
168
			}
169
			eval($pkg['custom_delete_php_command']);
170
		}
171
		header("Location:  pkg.php?xml=" . $xml);
172
		exit;
173
	}
174
}
175

    
176
ob_start();
177

    
178
$iflist = get_configured_interface_with_descr(false, true);
179
$evaledvar = $config['installedpackages'][xml_safe_fieldname($pkg['name'])]['config'];
180

    
181
if ($pkg['custom_php_global_functions'] != "") {
182
	eval($pkg['custom_php_global_functions']);
183
}
184

    
185
if ($pkg['custom_php_command_before_form'] != "") {
186
	eval($pkg['custom_php_command_before_form']);
187
}
188

    
189
// Breadcrumb
190
if ($pkg['title'] != "") {
191
	/*if (!$only_edit) {						// Is any package still making use of this?? Is this something that is still wanted, considering the breadcrumb policy https://redmine.pfsense.org/issues/5527
192
 		$pkg['title'] = $pkg['title'] . '/Edit';		// If this needs to live on, then it has to be moved to run AFTER "foreach ($pkg['tabs']['tab'] as $tab)"-loop. This due to $pgtitle[] = $tab['text']; 
193
	}*/
194
	if (strpos($pkg['title'], '/')) {
195
		$title = explode('/', $pkg['title']);
196

    
197
		foreach ($title as $subtitle) {
198
			$pgtitle[] = gettext($subtitle);
199
			$pglinks[] = "@self";
200
		}
201
	} else {
202
		$pgtitle = array(gettext("Package"), gettext($pkg['title']));
203
		$pglinks = array("", "@self");
204
	}
205
} else {
206
	$pgtitle = array(gettext("Package"), gettext("Editor"));
207
	$pglinks = array("", "@self");
208
}
209

    
210
if ($pkg['tabs'] != "") {
211
	$tab_array = array();
212
	foreach ($pkg['tabs']['tab'] as $tab) {
213
		if ($tab['tab_level']) {
214
			$tab_level = $tab['tab_level'];
215
		} else {
216
			$tab_level = 1;
217
		}
218
		if (isset($tab['active'])) {
219
			$active = true;
220
			$pgtitle[] = $tab['text'];
221
			$pglinks[] = "@self";
222
		} else {
223
			$active = false;
224
		}
225
		if (isset($tab['no_drop_down'])) {
226
			$no_drop_down = true;
227
		}
228
		$urltmp = "";
229
		if ($tab['url'] != "") {
230
			$urltmp = $tab['url'];
231
		}
232
		if ($tab['xml'] != "") {
233
			$urltmp = "pkg_edit.php?xml=" . $tab['xml'];
234
		}
235

    
236
		$addresswithport = getenv("HTTP_HOST");
237
		$colonpos = strpos($addresswithport, ":");
238
		if ($colonpos !== False) {
239
			//my url is actually just the IP address of the pfsense box
240
			$myurl = substr($addresswithport, 0, $colonpos);
241
		} else {
242
			$myurl = $addresswithport;
243
		}
244
		// eval url so that above $myurl item can be processed if need be.
245
		$url = str_replace('$myurl', $myurl, $urltmp);
246

    
247
		$tab_array[$tab_level][] = array(
248
			$tab['text'],
249
			$active,
250
			$url
251
		);
252
	}
253

    
254
	ksort($tab_array);
255
}
256

    
257
include("head.inc");
258
if (isset($tab_array)) {
259
	foreach ($tab_array as $tabid => $tab) {
260
		display_top_tabs($tab); //, $no_drop_down, $tabid);
261
	}
262
}
263

    
264
?>
265

    
266
<script type="text/javascript">
267
//<![CDATA[
268
events.push(function() {
269

    
270
	function setFilter(filtertext) {
271
		$('#pkg_filter').val(filtertext);
272
		document.pkgform.submit();
273
	}
274

    
275
<?php
276
	if ($pkg['adddeleteeditpagefields']['movable']) {
277
?>
278
		$('#mainarea table tbody').sortable({
279
		items: 'tr.sortable',
280
			cursor: 'move',
281
			distance: 10,
282
			opacity: 0.8,
283
			helper: function(e, ui) {
284
				ui.children().each(function() {
285
					$(this).width($(this).width());
286
				});
287
			return ui;
288
			},
289
		});
290
<?php
291
	}
292
?>
293
});
294

    
295
function save_changes_to_xml(xml) {
296
	var ids = $('#mainarea table tbody').sortable('serialize', {key:"ids[]"});
297
	var strloading="<?=gettext('Saving changes...')?>";
298
	if (confirm("<?=gettext("Confirmation Required to save changes.")?>")) {
299
		$.ajax({
300
			type: 'get',
301
			cache: false,
302
			url: "<?=$_SERVER['SCRIPT_NAME']?>",
303
			data: {xml:'<?=$xml?>', act:'update', ids: ids},
304
			beforeSend: function() {
305
				$('#savemsg').empty().html(strloading);
306
			},
307
			error: function(data) {
308
				$('#savemsg').empty().html('Error:' + data);
309
			},
310
			success: function(data) {
311
				$('#savemsg').empty().html(data);
312
			}
313
		});
314
	}
315
}
316

    
317
//]]>
318
</script>
319

    
320
<?php
321
if ($_GET['savemsg'] != "") {
322
	$savemsg = htmlspecialchars($_GET['savemsg']);
323
}
324

    
325
if ($savemsg) {
326
	print_info_box($savemsg, 'success');
327
}
328
?>
329

    
330
<form action="pkg.php" name="pkgform" method="get">
331
	<input type='hidden' name='xml' value='<?=$_REQUEST['xml']?>' />
332
		<div id="mainarea" class="panel panel-default">
333
			<table id="mainarea" class="table table-striped table-hover table-condensed">
334
				<thead>
335
<?php
336
	/* Handle filtering bar A-Z */
337
	$include_filtering_inputbox = false;
338
	$colspan = 0;
339
	if ($pkg['adddeleteeditpagefields']['columnitem'] != "") {
340
		foreach ($pkg['adddeleteeditpagefields']['columnitem'] as $column) {
341
			$colspan++;
342
		}
343
	}
344
	if ($pkg['fields']['field']) {
345
		// First find the sorting type field if it exists
346
		foreach ($pkg['fields']['field'] as $field) {
347
			if ($field['type'] == "sorting") {
348
				if (isset($field['include_filtering_inputbox'])) {
349
					$include_filtering_inputbox = true;
350
				}
351
				if ($display_maximum_rows < 1) {
352
					if ($field['display_maximum_rows']) {
353
						$display_maximum_rows = $field['display_maximum_rows'];
354
					}
355
				}
356
				echo "<tr><td colspan='$colspan' class='text-center'>";
357
				echo gettext("Filter by: ");
358
				$isfirst = true;
359
				for ($char = 65; $char < 91; $char++) {
360
					if (!$isfirst) {
361
						echo " | ";
362
					}
363
					echo "<a href=\"#\" onclick=\"setFilter('" . chr($char) . "');\">" . chr($char) . "</a>";
364
					$isfirst = false;
365
				}
366
				echo "</td></tr>";
367
				echo "<tr><td colspan='$colspan' class='text-center'>";
368
				if ($field['sortablefields']) {
369
					echo gettext("Filter field: ") . "<select name='pkg_filter_type'>";
370
					foreach ($field['sortablefields']['item'] as $si) {
371
						if ($si['name'] == $_REQUEST['pkg_filter_type']) {
372
							$SELECTED = "selected";
373
						} else {
374
							$SELECTED = "";
375
						}
376
						echo "<option value='{$si['name']}' {$SELECTED}>{$si['name']}</option>";
377
					}
378
					echo "</select>";
379
				}
380
				if ($include_filtering_inputbox) {
381
					echo '&nbsp;&nbsp;' . gettext("Filter text: ") . '<input id="pkg_filter" name="pkg_filter" value="' . htmlspecialchars($_REQUEST['pkg_filter']) . '" />';
382
					echo '&nbsp;<button type="submit" value="Filter" class="btn btn-primary btn-xs">';
383
					echo '<i class="fa fa-filter icon-embed-btn"></i>';
384
					echo gettext("Filter");
385
					echo "</button>";
386
				}
387
				echo "</td></tr><tr><td><font size='-3'>&nbsp;</font></td></tr>";
388
			}
389
		}
390
	}
391
?>
392
				<tr>
393

    
394
<?php
395
	if ($display_maximum_rows) {
396
		$totalpages = ceil(round((count($evaledvar) / $display_maximum_rows), 9));
397
		$page = 1;
398
		$tmpcount = 0;
399
		$tmppp = 0;
400
		if (is_array($evaledvar)) {
401
			foreach ($evaledvar as $ipa) {
402
				if ($tmpcount == $display_maximum_rows) {
403
					$page++;
404
					$tmpcount = 0;
405
				}
406
				if ($tmppp == $startdisplayingat) {
407
					break;
408
				}
409
				$tmpcount++;
410
				$tmppp++;
411
			}
412
		}
413
		echo "<tr><th colspan='" . count($pkg['adddeleteeditpagefields']['columnitem']) . "'>";
414
		echo "<table width='100%' summary=''>";
415
		echo "<tr>";
416
		echo "<td class='text-left'>" . sprintf(gettext('Displaying page %1$s of %2$s'), $page, $totalpages) . "</b></td>";
417
		echo "<td class='text-right'>" . gettext("Rows per page: ") . "<select onchange='document.pkgform.submit();' name='display_maximum_rows'>";
418
		for ($x = 0; $x < 250; $x++) {
419
			if ($x == $display_maximum_rows) {
420
				$SELECTED = "selected";
421
			} else {
422
				$SELECTED = "";
423
			}
424
			echo "<option value='$x' $SELECTED>$x</option>\n";
425
			$x = $x + 4;
426
		}
427
		echo "</select></td></tr>";
428
		echo "</table>";
429
		echo "</th></tr>";
430
	}
431

    
432
	$cols = 0;
433
	if ($pkg['adddeleteeditpagefields']['columnitem'] != "") {
434
		foreach ($pkg['adddeleteeditpagefields']['columnitem'] as $column) {
435
			echo "<th class=\"listhdrr\">" . $column['fielddescr'] . "</th>";
436
			$cols++;
437
		}
438
	}
439
?>
440
				</tr>
441
				</thead>
442
				<tbody>
443
<?php
444
	$i = 0;
445
	$pagination_counter = 0;
446
	if ($evaledvar) {
447
		foreach ($evaledvar as $ip) {
448
			if ($startdisplayingat) {
449
				if ($i < $startdisplayingat) {
450
					$i++;
451
					continue;
452
				}
453
			}
454
			if ($_REQUEST['pkg_filter']) {
455
				// Handle filtered items
456
				if ($pkg['fields']['field'] && !$filter_regex) {
457
					// First find the sorting type field if it exists
458
					foreach ($pkg['fields']['field'] as $field) {
459
						if ($field['type'] == "sorting") {
460
							if ($field['sortablefields']['item']) {
461
								foreach ($field['sortablefields']['item'] as $sf) {
462
									if ($sf['name'] == $_REQUEST['pkg_filter_type']) {
463
										$filter_fieldname = $sf['fieldname'];
464
										#Use a default regex on sortable fields when none is declared
465
										if ($sf['regex']) {
466
											$filter_regex = str_replace("%FILTERTEXT%", $_REQUEST['pkg_filter'], trim($sf['regex']));
467
										} else {
468
											$filter_regex = "/{$_REQUEST['pkg_filter']}/i";
469
										}
470
									}
471
								}
472
							}
473
						}
474
					}
475
				}
476
				// Do we have something to filter on?
477
				unset($filter_matches);
478
				if ($pkg['adddeleteeditpagefields']['columnitem'] != "") {
479
					foreach ($pkg['adddeleteeditpagefields']['columnitem'] as $column) {
480
						$fieldname = $ip[xml_safe_fieldname($column['fieldname'])];
481
						if ($column['fieldname'] == $filter_fieldname) {
482
							if ($filter_regex) {
483
								//echo "$filter_regex - $fieldname<p/>";
484
								preg_match($filter_regex, $fieldname, $filter_matches);
485
								break;
486
							}
487
						}
488
					}
489
				}
490
				if (!$filter_matches) {
491
					$i++;
492
					continue;
493
				}
494
			}
495
			if ($pkg['adddeleteeditpagefields']['movable']) {
496
				echo "<tr style=\"vertical-align: top\" class=\"sortable\" id=\"id_{$i}\">\n";
497
			} else {
498
				echo "<tr style=\"vertical-align: top\">\n";
499
			}
500
			if ($pkg['adddeleteeditpagefields']['columnitem'] != "") {
501
				foreach ($pkg['adddeleteeditpagefields']['columnitem'] as $column) {
502
					if ($column['fieldname'] == "description") {
503
						$class = "listbg";
504
					} else {
505
						$class = "listlr";
506
					}
507
?>
508
					<td class="<?=$class?>" ondblclick="document.location='pkg_edit.php?xml=<?=$xml?>&amp;act=edit&amp;id=<?=$i?>';">
509
<?php
510
					$fieldname = $ip[xml_safe_fieldname($column['fieldname'])];
511
					#Check if columnitem has a type field declared
512
					if ($column['type'] == "checkbox") {
513
						if ($fieldname == "") {
514
							echo gettext("No");
515
						} else {
516
							echo gettext("Yes");
517
						}
518
					} else if ($column['type'] == "interface") {
519
						echo $column['prefix'] . $iflist[$fieldname] . $column['suffix'];
520
					} else {
521
						$display_text = "";
522
						#Check if columnitem has an encoding field declared
523
						if ($column['encoding'] == "base64") {
524
							$display_text = $column['prefix'] . base64_decode($fieldname) . $column['suffix'];
525
						#Check if there is a custom info to show when $fieldname is not empty
526
						} else if ($column['listmodeon'] && $fieldname != "") {
527
							$display_text = $column['prefix'] . gettext($column['listmodeon']). $column['suffix'];
528
						#Check if there is a custom info to show when $fieldname is empty
529
						} else if ($column['listmodeoff'] && $fieldname == "") {
530
							$display_text = $column['prefix'] .gettext($column['listmodeoff']). $column['suffix'];
531
						} else {
532
							$display_text = $column['prefix'] . $fieldname ." ". $column['suffix'];
533
						}
534
						if (!isset($column['allow_html'])) {
535
							$display_text = htmlspecialchars($display_text);
536
						}
537
						echo $display_text;
538
					}
539
?>
540
					</td>
541
<?php
542
				} // foreach columnitem
543
			} // if columnitem
544
?>
545
					<td style="vertical-align: middle" class="list text-nowrap">
546
						<table border="0" cellspacing="0" cellpadding="1" summary="icons">
547
							<tr>
548
<?php
549
			#Show custom description to edit button if defined
550
			$edit_msg=($pkg['adddeleteeditpagefields']['edittext']?$pkg['adddeleteeditpagefields']['edittext']:gettext("Edit this item"));
551
?>
552
								<td><a class="fa fa-pencil" href="pkg_edit.php?xml=<?=$xml?>&amp;act=edit&amp;id=<?=$i?>" title="<?=$edit_msg?>"></a></td>
553
<?php
554
			#Show custom description to delete button if defined
555
			$delete_msg=($pkg['adddeleteeditpagefields']['deletetext']?$pkg['adddeleteeditpagefields']['deletetext']:gettext("Delete this item"));
556
?>
557
								<td>&nbsp;<a class="fa fa-trash" href="pkg.php?xml=<?=$xml?>&amp;act=del&amp;id=<?=$i?>" title="<?=$delete_msg?>"></a></td>
558
							</tr>
559
						</tbody>
560
					</table>
561
				</td>
562
<?php
563
			echo "</tr>\n"; // Pairs with an echo tr some way above
564
			// Handle pagination and display_maximum_rows
565
			if ($display_maximum_rows) {
566
				if ($pagination_counter == ($display_maximum_rows-1) or
567
					$i == (count($evaledvar)-1)) {
568
					$colcount = count($pkg['adddeleteeditpagefields']['columnitem']);
569
					$final_footer = "";
570
					$final_footer .= "<tr><td colspan='$colcount'>";
571
					$final_footer .= "<table width='100%' summary=''><tr>";
572
					$final_footer .= "<td class='text-left'>";
573
					$startingat = $startdisplayingat - $display_maximum_rows;
574
					if ($startingat > -1) {
575
						$final_footer .= "<a href='pkg.php?xml=" . $_REQUEST['xml'] . "&amp;startdisplayingat={$startingat}&amp;display_maximum_rows={$display_maximum_rows}'>";
576
					} else if ($startdisplayingat > 1) {
577
						$final_footer .= "<a href='pkg.php?xml=" . $_REQUEST['xml'] . "&amp;startdisplayingat=0&amp;display_maximum_rows={$display_maximum_rows}'>";
578
					}
579
					$final_footer .= "<font size='2'><< " . gettext("Previous page") . "</font></a>";
580
					if ($tmppp + $display_maximum_rows > count($evaledvar)) {
581
						$endingrecord = count($evaledvar);
582
					} else {
583
						$endingrecord = $tmppp + $display_maximum_rows;
584
					}
585
					$final_footer .= "</td><td class='text-center'>";
586
					$tmppp++;
587
					$final_footer .= "<font size='2'>Displaying {$tmppp} - {$endingrecord} / " . count($evaledvar) . " records";
588
					$final_footer .= "</font></td><td class='text-right'>&nbsp;";
589
					if (($i+1) < count($evaledvar)) {
590
						$final_footer .= "<a href='pkg.php?xml=" . $_REQUEST['xml'] . "&amp;startdisplayingat=" . ($startdisplayingat + $display_maximum_rows) . "&amp;display_maximum_rows={$display_maximum_rows}'>";
591
					}
592
					$final_footer .= "<font size='2'>" . gettext("Next page") . " >></font></a>";
593
					$final_footer .= "</td></tr></table></td></tr>";
594
					$i = count($evaledvar);
595
					break;
596
				}
597
			}
598
			$i++;
599
			$pagination_counter++;
600
		} // foreach evaledvar
601
	} // if evaledvar
602
?>
603
				<tr>
604
					<td colspan="<?=$cols?>"></td>
605
					<td>
606
						<table border="0" cellspacing="0" cellpadding="1" summary="icons">
607
							<tr>
608
<?php
609
	#Show custom description to add button if defined
610
	$add_msg=($pkg['adddeleteeditpagefields']['addtext']?$pkg['adddeleteeditpagefields']['addtext']:gettext("Add a new item"));
611
?>
612
								<td><a href="pkg_edit.php?xml=<?=$xml?>&amp;id=<?=$i?>" class="btn btn-sm btn-success" title="<?=$add_msg?>"><i class="fa fa-plus icon-embed-btn"></i><?=gettext('Add')?></a></td>
613
<?php
614
	#Show description button and info if defined
615
	if ($pkg['adddeleteeditpagefields']['description']) {
616
?>
617
								<td>
618
									<i class="fa fa-info-circle"><?=$pkg['adddeleteeditpagefields']['description']?></i>
619
								</td>
620
<?php
621
	}
622
?>
623
							</tr>
624
						</table>
625
					</td>
626
				</tr>
627
				<?=$final_footer?>
628
			</table>
629
			</div>
630
		<button class="btn btn-primary" type="button" value="Save" name="Submit" onclick="save_changes_to_xml('<?=$xml?>')"><i class="fa fa-save icon-embed-btn"></i><?=gettext("Save")?></button>
631

    
632
</form>
633
<?php
634
echo "<!-- filter_fieldname: {$filter_fieldname} -->";
635
echo "<!-- filter_regex: {$filter_regex} -->";
636

    
637
include("foot.inc"); ?>
(97-97/225)