Merge branch 'master' of github.com:ZoneMinder/zoneminder

pull/4020/head
Isaac Connor 2024-05-21 09:20:28 -04:00
commit 32ae42ecf2
6 changed files with 138 additions and 38 deletions

View File

@ -21,9 +21,9 @@ require_once('includes/MontageLayout.php');
if ( isset($_REQUEST['object']) ) {
if ( $_REQUEST['object'] == 'MontageLayout' ) {
if ($action == 'Save') {
$Layout = null;
$Layout = null;
if ($action == 'Save') {
# Name is only populated when creating a new layout
if ( $_REQUEST['Name'] != '' ) {
$Layout = new ZM\MontageLayout();
@ -44,7 +44,35 @@ if ( isset($_REQUEST['object']) ) {
ZM\Warning('Need System permissions to edit layouts');
return;
}
} // end if save
} else if ($action == 'Delete') { // end if save
if ( isset($_REQUEST['zmMontageLayout']) ) {
$Layout = new ZM\MontageLayout($_REQUEST['zmMontageLayout']);
} else {
ZM\Warning('Name of layout to be deleted is not specified');
return;
}
if (canEdit('System')) {
if ($Layout->Id()) {
$Layout->delete();
zm_session_start();
unset($_SESSION["zmMontageLayout"]);
$_SESSION['zmMontageLayout'] = '';
session_write_close();
unset($_COOKIE['zmMontageLayout']);
zm_setcookie('zmMontageLayout', '', array('expires'=>time()-3600*24)); //!!! After this JS still sees cookies, strange !!!
$redirect = '?view=montage';
} else {
ZM\Warning('Layout Id=' . $_REQUEST['zmMontageLayout'] . ' not found for delete');
$redirect = '?view=montage';
}
} else {
ZM\Warning('Need System permissions to delete layouts');
$redirect = '?view=montage';
}
} else {// end if delete
ZM\Warning("Unsupported action $action in montage");
} // end if else
} # end if isset($_REQUEST['object'] )
} # end if isset($_REQUEST['object'] )
?>

View File

@ -220,6 +220,7 @@ $SLANG = array(
'ConfirmDeleteControl' => 'Warning, deleting a control will reset all monitors that use it to be uncontrollable.<br><br>Are you sure you wish to delete?',
'ConfirmDeleteDevices' => 'Are you sure you wish to delete the selected devices?',
'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?',
'ConfirmDeleteLayout' => 'Are you sure you wish to delete current layout?',
'ConfirmDeleteTitle' => 'Delete Confirmation',
'ConfirmPassword' => 'Confirm Password',
'ConfirmUnarchiveEvents'=> 'Are you sure you wish to unarchive the selected events?',

View File

@ -226,6 +226,7 @@ $SLANG = array(
'Config' => 'Config',
'ConfiguredFor' => 'Configuré pour',
'ConfirmDeleteEvents' => 'Etes-vous sûr de vouloir effacer le(s) événement(s) sélectionné(s)?',
'ConfirmDeleteLayout' => 'Êtes-vous sûr de vouloir supprimer la mise en page actuelle ?',
'ConfirmPassword' => 'Répéter mot de passe',
'ConjAnd' => 'et',
'ConjOr' => 'ou',

View File

@ -246,6 +246,7 @@ $SLANG = array(
'Config' => 'Конфигурация',
'ConfiguredFor' => 'настроен на',
'ConfirmDeleteEvents' => 'Вы действительно хотите удалить выбранные события?',
'ConfirmDeleteLayout' => 'Вы действительно хотите удалить текущий шаблон?',
'ConfirmPassword' => 'Подтвердите пароль',
'ConfirmUnarchiveEvents'=> 'Вы уверены, что хотите удалить из архива выбранные события?',
'ConjAnd' => 'и',

View File

@ -53,7 +53,7 @@ function stringToNumber(str) {
}
function isPresetLayout(name) {
return (( name=='Freeform' || name=='1 Wide' || name=='2 Wide' || name=='3 Wide' || name=='4 Wide' || name=='6 Wide' || name=='8 Wide' || name=='12 Wide' || name=='16 Wide' ) ? true : false);
return ((ZM_PRESET_LAYOUT_NAMES.indexOf(name) != -1) ? true : false);
}
function getCurrentNameLayout() {
@ -137,6 +137,7 @@ function selectLayout(new_layout_id) {
}
if (isPresetLayout(nameLayout)) { //PRESET
document.getElementById("btnDeleteLayout").setAttribute('disabled', '');
setSelected(document.getElementById("ratio"), getCookie('zmMontageRatioForAll'));
changeRatioForAll();
@ -158,6 +159,7 @@ function selectLayout(new_layout_id) {
}
initGridStack();
} else { //CUSTOM
document.getElementById("btnDeleteLayout").removeAttribute('disabled');
for (let i = 0, length = monitors.length; i < length; i++) {
const monitor = monitors[i];
// Need to clear the current positioning, and apply the new
@ -409,6 +411,7 @@ function save_layout(button) {
Positions['monitorRatio'][stringToNumber(this.id)] = getSelected(this);
});
form.Positions.value = JSON.stringify(Positions, null, ' ');
$j('#action').attr('value', 'Save');
form.submit();
} // end function save_layout
@ -436,6 +439,53 @@ function cancel_layout(button) {
selectLayout();
}
function delete_layout(button) {
if (!canEdit.System) {
enoperm();
return;
}
if (!document.getElementById('deleteConfirm')) {
// Load the delete confirmation modal into the DOM
// $j.getJSON(thisUrl + '?request=modal&modal=delconfirm')
$j.getJSON(thisUrl + '?request=modal&modal=delconfirm', {
key: 'ConfirmDeleteLayout',
})
.done(function(data) {
insertModalHtml('deleteConfirm', data.html);
manageDelConfirmModalBtns();
$j('#deleteConfirm').modal('show');
})
.fail(function(jqXHR) {
console.log('error getting delconfirm', jqXHR);
logAjaxFail(jqXHR);
});
return;
} else {
$j('#deleteConfirm').modal('show');
}
} // end function delete_layout
// Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() {
document.getElementById('delConfirmBtn').addEventListener('click', function onDelConfirmClick(evt) {
document.getElementById('delConfirmBtn').disabled = true; // prevent double click
if (!canEdit.Monitors) {
enoperm();
return;
}
evt.preventDefault();
const form = $j('#btnDeleteLayout')[0].form;
$j('#action').attr('value', 'Delete');
form.submit();
});
// Manage the CANCEL modal button
document.getElementById('delCancelBtn').addEventListener('click', function onDelCancelClick(evt) {
$j('#deleteConfirm').modal('hide');
});
}
function reloadWebSite(ndx) {
document.getElementById('imageFeed'+ndx).innerHTML = document.getElementById('imageFeed'+ndx).innerHTML;
}
@ -656,9 +706,9 @@ function initPage() {
$j("#flipMontageHeader").slideToggle("fast");
$j("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
}
if (getCookie('zmMontageLayout')) {
$j('#zmMontageLayout').val(getCookie('zmMontageLayout'));
}
// if (getCookie('zmMontageLayout')) { //This is implemented in montage.php And the cookies may contain the number of a non-existent Layouts!!!
// $j('#zmMontageLayout').val(getCookie('zmMontageLayout'));
// }
$j(".grid-monitor").hover(
//Displaying "Scale" and other buttons at the top of the monitor image

View File

@ -60,6 +60,18 @@ $monitorStatusPositon = array(
$monitorStatusPositonSelected = 'outsideImgBottom';
$presetLayoutsNames = array( //Order matters!
'Freeform',
'1 Wide',
'2 Wide',
'3 Wide',
'4 Wide',
'6 Wide',
'8 Wide',
'12 Wide',
'16 Wide'
);
if (isset($_REQUEST['monitorStatusPositonSelected'])) {
$monitorStatusPositonSelected = $_REQUEST['monitorStatusPositonSelected'];
} else if (isset($_COOKIE['zmMonitorStatusPositonSelected'])) {
@ -69,16 +81,30 @@ if (isset($_REQUEST['monitorStatusPositonSelected'])) {
$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')"));
$layoutsById = array();
$FreeFormLayoutId = 0;
/* Create an array "Name"=>"Id" to make it easier to find IDs by name*/
$arrNameId = array();
foreach ($layouts as $l) {
$arrNameId[$l->Name()] = $l->Id();
}
/* Fill with preinstalled Layouts. They should always come first */
foreach ($presetLayoutsNames as $name) {
if (array_key_exists($name, $arrNameId)) // Layout may be missing in BD (rare case during update process)
$layoutsById[$arrNameId[$name]] = $name; //We will only assign a name, which is necessary for the sorting order. We will replace it with an object in the next loop.
}
/* For some reason $layouts is already sorted by ID and requires analysis. But just in case, we will sort by ID */
uasort($layouts, function($a, $b) {
return $a->Id <=> $b->Id;
});
/* Add custom Layouts & assign objects instead of names for preset Layouts */
foreach ( $layouts as $l ) {
if ( $l->Name() == 'Freeform' ) {
$FreeFormLayoutId = $l->Id();
$layoutsById[$l->Id()] = $l;
break;
}
}
foreach ( $layouts as $l ) {
if ( $l->Name() != 'Freeform' )
$layoutsById[$l->Id()] = $l;
$layoutsById[$l->Id()] = $l;
}
zm_session_start();
@ -173,30 +199,20 @@ foreach ($displayMonitors as &$row) {
}
} # end foreach Monitor
if (!$layout_id) {
if (!$layout_id || !is_numeric($layout_id) || !isset($layoutsById[$layout_id])) {
$default_layout = '';
if (!$default_layout) {
if ((count($monitors) > 5) and (count($monitors)%5 == 0)) {
$default_layout = '5 Wide';
} else if ((count($monitors) > 4) and (count($monitors)%4 == 0)) {
$default_layout = '4 Wide';
} else if (count($monitors)%3 == 0) {
$default_layout = '3 Wide';
} else {
$default_layout = '2 Wide';
}
}
foreach ($layouts as $l) {
if ($l->Name() == $default_layout) {
$layout_id = $l->Id();
}
if (count($monitors) > 6) {
$default_layout = '6 Wide';
} else if (count($monitors) > 4) {
$default_layout = '4 Wide';
} else {
$default_layout = '2 Wide';
}
$layout_id = $arrNameId[$default_layout];
}
$Layout = '';
$Positions = '';
if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) {
$Layout = $layoutsById[$layout_id];
$Positions = json_decode($Layout->Positions(), true);
} else {
ZM\Debug('Layout not found');
}
@ -242,7 +258,7 @@ if (canView('System')) {
<div id="sizeControl">
<form action="?view=montage" method="post">
<input type="hidden" name="object" value="MontageLayout"/>
<input type="hidden" name="action" value="Save"/>
<input id="action" type="hidden" name="action" value=""/> <?php // "value" is generated in montage.js depending on the action "Save" or "Delete"?>
<span id="monitorStatusPositonControl">
<label><?php echo translate('Monitor status position') ?></label>
@ -250,17 +266,17 @@ if (canView('System')) {
</span>
<span id="ratioControl">
<label><?php echo translate('Ratio') ?></label>
<?php echo htmlSelect('ratio', '', '', array('id'=>'ratio', 'data-on-change'=>'changeRatioForAll', 'class'=>'chosen')); ?>
<?php echo htmlSelect('ratio', [], '', array('id'=>'ratio', 'data-on-change'=>'changeRatioForAll', 'class'=>'chosen')); ?>
</span>
<span id="widthControl" class="hidden">
<span id="widthControl" class="hidden"> <!-- OLD version, requires removal -->
<label><?php echo translate('Width') ?></label>
<?php echo htmlSelect('width', $widths, 'auto'/*$options['width']*/, array('id'=>'width', 'data-on-change'=>'changeWidth', 'class'=>'chosen')); ?>
</span>
<span id="heightControl" class="hidden">
<span id="heightControl" class="hidden"> <!-- OLD version, requires removal -->
<label><?php echo translate('Height') ?></label>
<?php echo htmlSelect('height', $heights, 'auto'/*$options['height']*/, array('id'=>'height', 'data-on-change'=>'changeHeight', 'class'=>'chosen')); ?>
</span>
<span id="scaleControl" class="hidden">
<span id="scaleControl" class="hidden"> <!-- OLD version, requires removal -->
<label><?php echo translate('Scale') ?></label>
<?php echo htmlSelect('scale', $scales, '0'/*$scale*/, array('id'=>'scale', 'data-on-change-this'=>'changeScale', 'class'=>'chosen')); ?>
</span>
@ -270,6 +286,7 @@ if (canView('System')) {
</span>
<input type="hidden" name="Positions"/>
<button type="button" id="EditLayout" data-on-click-this="edit_layout"><?php echo translate('EditLayout') ?></button>
<button type="button" id="btnDeleteLayout" class="btn btn-danger" value="Delete" data-on-click-this="delete_layout" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete layout') ?>" disabled><i class="material-icons md-18">delete</i></button>
<span id="SaveLayout" style="display:none;">
<input type="text" name="Name" placeholder="Enter new name for layout if desired" autocomplete="off"/>
<button type="button" value="Save" data-on-click-this="save_layout"><?php echo translate('Save') ?></button>
@ -325,6 +342,8 @@ foreach ($monitors as $monitor) {
<script src="<?php echo cache_bust('js/MonitorStream.js') ?>"></script>
<?php xhtmlFooter() ?>
<?php echo '<script nonce="'.$cspNonce.'"> const ZM_PRESET_LAYOUT_NAMES = '.json_encode($presetLayoutsNames).' </script>'.PHP_EOL;?>
<!-- In May 2024, IgorA100 globally changed grid layout -->
<div id="messageModal" class="modal fade" tabindex="-1">
<div class="modal-dialog">