core/src/www/index.php

434 lines
18 KiB
PHP

<?php
/*
* Copyright (C) 2014-2016 Deciso B.V.
* Copyright (C) 2004-2012 Scott Ullrich <sullrich@gmail.com>
* Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once('guiconfig.inc');
// if no config entry found, initialize config entry
config_read_array('widgets');
$widgetCollection = array();
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$pconfig = $config['widgets'];
legacy_html_escape_form_data($pconfig);
// set default dashboard view
$pconfig['sequence'] = !empty($pconfig['sequence']) ? $pconfig['sequence'] : '';
$pconfig['column_count'] = !empty($pconfig['column_count']) ? $pconfig['column_count'] : 2;
// build list of widgets
$widgetSeqParts = explode(",", $pconfig['sequence']);
foreach (glob('/usr/local/www/widgets/widgets/*.widget.php') as $php_file) {
$widgetItem = array();
$widgetItem['name'] = basename($php_file, '.widget.php');
$widgetItem['display_name'] = ucwords(str_replace("_", " ", $widgetItem['name']));
$widgetItem['filename'] = $php_file;
$widgetItem['state'] = "none";
/// default sort order
$widgetItem['sortKey'] = $widgetItem['name'] == 'system_information' ? "00000000" : "99999999" . $widgetItem['name'];
foreach ($widgetSeqParts as $seqPart) {
$tmp = explode(':', $seqPart);
if (count($tmp) == 3 && explode('-', $tmp[0])[0] == $widgetItem['name']) {
$widgetItem['state'] = $tmp[2];
$widgetItem['sortKey'] = $tmp[1];
}
}
$widgetCollection[] = $widgetItem;
}
// sort widgets
usort($widgetCollection, function ($item1, $item2) {
return strcmp(strtolower($item1['sortKey']), strtolower($item2['sortKey']));
});
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['origin']) && $_POST['origin'] == 'dashboard') {
if (!empty($_POST['sequence'])) {
$config['widgets']['sequence'] = $_POST['sequence'];
} elseif (isset($config['widgets']['sequence'])) {
unset($config['widgets']['sequence']);
}
if (!empty($_POST['column_count'])) {
$config['widgets']['column_count'] = filter_var($_POST['column_count'], FILTER_SANITIZE_NUMBER_INT);
} elseif(isset($config['widgets']['column_count'])) {
unset($config['widgets']['column_count']);
}
write_config('Widget configuration has been changed');
header(url_safe('Location: /index.php'));
exit;
}
// handle widget includes
foreach (glob("/usr/local/www/widgets/include/*.inc") as $filename) {
include($filename);
}
$product = product::getInstance();
include("head.inc");
?>
<body>
<?php
include("fbegin.inc");?>
<?php
?>
<?php
if (isset($config['trigger_initial_wizard']) || isset($_GET['wizard_done'])): ?>
<script>
$( document ).ready(function() {
$(".page-content-head:first").hide();
});
</script>
<header class="page-content-head">
<div class="container-fluid">
<?php
if (isset($config['trigger_initial_wizard'])): ?>
<h1><?= gettext("Starting initial configuration!") ?></h1>
<?php
else: ?>
<h1><?= gettext("Finished initial configuration!") ?></h1>
<?php
endif ?>
</div>
</header>
<section class="page-content-main">
<div class="container-fluid col-xs-12 col-sm-10 col-md-9">
<div class="row">
<section class="col-xs-12">
<div class="content-box wizard" style="padding: 20px;">
<div class="table-responsive">
<?php if (file_exists("/usr/local/opnsense/www/themes/{$themename}/build/images/default-logo.svg")): ?>
<img src=" <?= cache_safe("/ui/themes/{$themename}/build/images/default-logo.svg") ?>" border="0" alt="logo" style="max-width:380px;" />
<?php else: ?>
<img src=" <?= cache_safe("/ui/themes/{$themename}/build/images/default-logo.png") ?>" border="0" alt="logo" style="max-width:380px;" />
<?php endif ?>
<br />
<div class="content-box-main" style="padding-bottom:0px;">
<?php
if (isset($config['trigger_initial_wizard'])) {
echo '<p>' . sprintf(gettext('Welcome to %s!'), $product->name()) . "</p>\n";
echo '<p>' . gettext('One moment while we start the initial setup wizard.') . "</p>\n";
echo '<p class="__nomb">' . gettext('To bypass the wizard, click on the logo in the upper left corner.') . "</p>\n";
} else {
echo '<p>' . sprintf(gettext('Congratulations! %s is now configured.'), $product->name()) . "</p>\n";
echo '<p>' . sprintf(gettext(
'Please consider donating to the project to help us with our overhead costs. ' .
'See %sour website%s to donate or purchase available %s support services.'),
'<a target="_new" href="' . $product->website() . '">', '</a>', $product->name()) . "</p>\n";
echo '<p class="__nomb">' . sprintf(gettext('Click to %scontinue to the dashboard%s.'), '<a href="/">', '</a>') . ' ';
echo sprintf(gettext('Or click to %scheck for updates%s.'), '<a href="/ui/core/firmware#checkupdate">', '</a>'). "</p>\n";
}
?>
</div>
<div>
</div>
</section>
</div>
</div>
</section>
<?php
if (isset($config['trigger_initial_wizard'])): ?>
<meta http-equiv="refresh" content="5;url=/wizard.php?xml=system">
<?php
endif ?>
<?php
// normal dashboard
else:?>
<script src="<?= cache_safe('/ui/js/jquery-sortable.js') ?>"></script>
<script>
function addWidget(selectedDiv) {
$('#'+selectedDiv).show();
$('#add_widget_'+selectedDiv).hide();
$('#'+selectedDiv+'-config').val('show');
showSave();
}
function configureWidget(selectedDiv) {
let selectIntLink = '#' + selectedDiv + "-settings";
if ($(selectIntLink).css('display') == "none") {
$(selectIntLink).show();
} else {
$(selectIntLink).hide();
}
}
function showWidget(selectedDiv,swapButtons) {
$('#'+selectedDiv+'-container').show();
$('#'+selectedDiv+'-min').show();
$('#'+selectedDiv+'-max').hide();
$('#'+selectedDiv+'-config').val('show');
showSave();
}
function minimizeWidget(selectedDiv, swapButtons) {
$('#'+selectedDiv+'-container').hide();
$('#'+selectedDiv+'-min').hide();
$('#'+selectedDiv+'-max').show();
$('#'+selectedDiv+'-config').val('hide');
showSave();
}
function closeWidget(selectedDiv) {
$('#'+selectedDiv).hide();
$('#'+selectedDiv+'-config').val('close');
showSave();
}
function showSave() {
$('#updatepref').show();
}
function updatePref() {
var widgetInfo = [];
var index = 0;
$('.widgetdiv').each(function(key) {
if ($(this).is(':visible')) {
// only capture visible widgets
var index_str = "0000000" + index;
index_str = index_str.substr(index_str.length-8);
let col_index = $(this).parent().attr("id").split('_')[1];
widgetInfo.push($(this).attr('id')+'-container:'+index_str+'-'+col_index+':'+$('input[name='+$(this).attr('id')+'-config]').val());
index++;
}
});
$("#sequence").val(widgetInfo.join(','));
$("#iform").submit();
return false;
}
/**
* ajax update widget data, searches data-plugin attributes and use function in data-callback to update widget
*/
function process_widget_data()
{
var plugins = [];
var callbacks = [];
// collect plugins and callbacks
$("[data-plugin]").each(function(){
if (plugins.indexOf($(this).data('plugin')) < 0) {
plugins.push($(this).data('plugin'));
}
if ($(this).data('callback') != undefined) {
callbacks.push({'function' : $(this).data('callback'), 'plugin': $(this).data('plugin'), 'sender': $(this)});
}
});
// collect data for provided plugins
$.ajax("/widgets/api/get.php",{type: 'get', cache: false, dataType: "json", data: {'load': plugins.join(',')}})
.done(function(response) {
callbacks.map( function(callback) {
try {
if (response['data'][callback['plugin']] != undefined) {
window[callback['function']](callback['sender'], response['data'][callback['plugin']]);
}
} catch (err) {
console.log(err);
}
});
// schedule next update
setTimeout('process_widget_data()', 5000);
});
}
</script>
<script>
$( document ).ready(function() {
// rearrange widgets to stored column
$(".widgetdiv").each(function(){
var widget = $(this);
widget.find('script').each(function(){
$(this).remove();
});
var container = $(this).parent();
var target_col = widget.data('sortkey').split('-')[1];
if (target_col != undefined) {
if (container.attr('id').split('_')[1] != target_col) {
widget.remove().appendTo("#dashboard_"+target_col);
}
} else {
// dashboard_colx (source) is not visible, move other items to col4
widget.remove().appendTo("#dashboard_col4");
}
});
// show dashboard widgets after initial rendering
$("#dashboard_container").show();
// trigger WidgetsReady event
$("#dashboard_container").trigger("WidgetsReady");
// sortable widgets
$(".dashboard_grid_column").sortable({
handle: '.widget-sort-handle',
group: 'dashboard_grid_column',
itemSelector: '.widgetdiv',
containerSelector: '.dashboard_grid_column',
placeholder: '<div class="placeholder"><i class="fa fa-hand-o-right" aria-hidden="true"></i></div>',
afterMove: function (placeholder, container, closestItemOrContainer) {
showSave();
}
});
// select number of columns
$("#column_count").change(function(){
if ($("#column_count_input").val() != $("#column_count").val()) {
showSave();
}
$("#column_count_input").val($("#column_count").val());
$(".dashboard_grid_column").each(function(){
var widget_col = $(this);
$.each(widget_col.attr("class").split(' '), function(index, classname) {
if (classname.indexOf('col-md') > -1) {
widget_col.removeClass(classname);
}
});
widget_col.addClass('col-md-'+(12 / $("#column_count_input").val()));
});
});
$("#column_count").change();
// trigger initial ajax data poller
process_widget_data();
// in "Add Widget" dialog, hide widgets already on screen
$("#add_widget_btn").click(function(){
$(".widgetdiv").each(function(widget){
if ($(this).is(':visible')) {
$("#add_widget_" + $(this).attr('id')).hide();
} else {
$("#add_widget_" + $(this).attr('id')).show();
}
});
});
$('.selectpicker_widget').selectpicker('refresh');
});
</script>
<section class="page-content-main">
<form method="post" id="iform">
<input type="hidden" value="dashboard" name="origin" id="origin" />
<input type="hidden" value="" name="sequence" id="sequence" />
<input type="hidden" value="<?= $pconfig['column_count'];?>" name="column_count" id="column_count_input" />
</form>
<div class="container-fluid">
<div class="row">
<div class="col-md-12 col-xs-12">
<?php print_service_banner('bootup') ?>
<?php print_service_banner('livecd') ?>
</div>
</div>
<div id="dashboard_container" class="row" style="display:none">
<div class="col-xs-12 col-md-2 dashboard_grid_column hidden" id="dashboard_colx">
<?php
foreach ($widgetCollection as $widgetItem):
$widgettitle = $widgetItem['name'] . "_title";
$widgettitlelink = $widgetItem['name'] . "_title_link";
switch ($widgetItem['state']) {
case "show":
$divdisplay = "block";
$display = "block";
$inputdisplay = "show";
$mindiv = "inline";
break;
case "hide":
$divdisplay = "block";
$display = "none";
$inputdisplay = "hide";
$mindiv = "none";
break;
case "close":
$divdisplay = "none";
$display = "block";
$inputdisplay = "close";
$mindiv = "inline";
break;
default:
$divdisplay = "none";
$display = "block";
$inputdisplay = "none";
$mindiv = "inline";
break;
}?>
<section class="widgetdiv" data-sortkey="<?=$widgetItem['sortKey'] ?>" id="<?=$widgetItem['name'];?>" style="display:<?=$divdisplay;?>;">
<div class="content-box">
<header class="content-box-head container-fluid">
<ul class="list-inline __nomb">
<li><h3>
<?php
// XXX: ${$} is intentional here, the widgets leave global vars [widget_name]_title_link and [widget_name]_title
if (isset(${$widgettitlelink})):?>
<u><span onclick="location.href='/<?= html_safe(${$widgettitlelink}) ?>'" style="cursor:pointer">
<?php
endif;
echo empty(${$widgettitle}) ? $widgetItem['display_name'] : ${$widgettitle};
if (isset(${$widgettitlelink})):?>
</span></u>
<?php
endif;?>
</h3></li>
<li class="pull-right">
<div class="btn-group">
<button type="button" class="btn btn-default btn-xs disabled" id="<?= $widgetItem['name'] ?>-configure" onclick='return configureWidget("<?= $widgetItem['name'] ?>")' style="cursor:pointer"><i class="fa fa-pencil fa-fw"></i></button>
<button type="button" class="btn btn-default btn-xs" title="minimize" id="<?= $widgetItem['name'] ?>-min" onclick='return minimizeWidget("<?= $widgetItem['name'] ?>",true)' style="display:<?= $mindiv ?>;"><i class="fa fa-minus fa-fw"></i></button>
<button type="button" class="btn btn-default btn-xs" title="maximize" id="<?= $widgetItem['name'] ?>-max" onclick='return showWidget("<?= $widgetItem['name'] ?>",true)' style="display:<?= $mindiv == 'none' ? 'inline' : 'none' ?>;"><i class="fa fa-plus fa-fw"></i></button>
<button type="button" class="btn btn-default btn-xs" title="remove widget" onclick='return closeWidget("<?= $widgetItem['name'] ?>",true)'><i class="fa fa-remove fa-fw"></i></button>
</div>
</li>
</ul>
<div class="container-fluid widget-sort-handle">
</div>
</header>
<div class="content-box-main collapse in" id="<?= $widgetItem['name'] ?>-container" style="display:<?= $mindiv ?>">
<input type="hidden" value="<?= $inputdisplay ?>" id="<?= $widgetItem['name'] ?>-config" name="<?= $widgetItem['name'] ?>-config" />
<?php
if ($divdisplay != "block"):?>
<div id="<?= $widgetItem['name'] ?>-loader" style="display:<?= $display ?>;">
&nbsp;&nbsp;<i class="fa fa-refresh"></i> <?= gettext("Save to load widget") ?>
</div>
<?php
else:
include($widgetItem['filename']);
endif;
?>
</div>
</div>
</section>
<?php
endforeach;?>
</div>
<div class="col-md-2 dashboard_grid_column" id="dashboard_col1"></div>
<div class="col-md-2 dashboard_grid_column" id="dashboard_col2"></div>
<div class="col-md-2 dashboard_grid_column" id="dashboard_col3"></div>
<div class="col-md-2 dashboard_grid_column" id="dashboard_col4"></div>
<div class="col-md-2 dashboard_grid_column" id="dashboard_col5"></div>
<div class="col-md-2 dashboard_grid_column" id="dashboard_col6"></div>
</div>
</div>
</section>
<?php endif;
include("foot.inc");