Merge branch 'master' of github.com:ZoneMinder/zoneminder
commit
32ae42ecf2
|
@ -21,9 +21,9 @@ require_once('includes/MontageLayout.php');
|
||||||
|
|
||||||
if ( isset($_REQUEST['object']) ) {
|
if ( isset($_REQUEST['object']) ) {
|
||||||
if ( $_REQUEST['object'] == 'MontageLayout' ) {
|
if ( $_REQUEST['object'] == 'MontageLayout' ) {
|
||||||
if ($action == 'Save') {
|
$Layout = null;
|
||||||
$Layout = null;
|
|
||||||
|
|
||||||
|
if ($action == 'Save') {
|
||||||
# Name is only populated when creating a new layout
|
# Name is only populated when creating a new layout
|
||||||
if ( $_REQUEST['Name'] != '' ) {
|
if ( $_REQUEST['Name'] != '' ) {
|
||||||
$Layout = new ZM\MontageLayout();
|
$Layout = new ZM\MontageLayout();
|
||||||
|
@ -44,7 +44,35 @@ if ( isset($_REQUEST['object']) ) {
|
||||||
ZM\Warning('Need System permissions to edit layouts');
|
ZM\Warning('Need System permissions to edit layouts');
|
||||||
return;
|
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'] )
|
||||||
} # end if isset($_REQUEST['object'] )
|
} # end if isset($_REQUEST['object'] )
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -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?',
|
'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?',
|
'ConfirmDeleteDevices' => 'Are you sure you wish to delete the selected devices?',
|
||||||
'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?',
|
'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?',
|
||||||
|
'ConfirmDeleteLayout' => 'Are you sure you wish to delete current layout?',
|
||||||
'ConfirmDeleteTitle' => 'Delete Confirmation',
|
'ConfirmDeleteTitle' => 'Delete Confirmation',
|
||||||
'ConfirmPassword' => 'Confirm Password',
|
'ConfirmPassword' => 'Confirm Password',
|
||||||
'ConfirmUnarchiveEvents'=> 'Are you sure you wish to unarchive the selected events?',
|
'ConfirmUnarchiveEvents'=> 'Are you sure you wish to unarchive the selected events?',
|
||||||
|
|
|
@ -226,6 +226,7 @@ $SLANG = array(
|
||||||
'Config' => 'Config',
|
'Config' => 'Config',
|
||||||
'ConfiguredFor' => 'Configuré pour',
|
'ConfiguredFor' => 'Configuré pour',
|
||||||
'ConfirmDeleteEvents' => 'Etes-vous sûr de vouloir effacer le(s) événement(s) sélectionné(s)?',
|
'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',
|
'ConfirmPassword' => 'Répéter mot de passe',
|
||||||
'ConjAnd' => 'et',
|
'ConjAnd' => 'et',
|
||||||
'ConjOr' => 'ou',
|
'ConjOr' => 'ou',
|
||||||
|
|
|
@ -246,6 +246,7 @@ $SLANG = array(
|
||||||
'Config' => 'Конфигурация',
|
'Config' => 'Конфигурация',
|
||||||
'ConfiguredFor' => 'настроен на',
|
'ConfiguredFor' => 'настроен на',
|
||||||
'ConfirmDeleteEvents' => 'Вы действительно хотите удалить выбранные события?',
|
'ConfirmDeleteEvents' => 'Вы действительно хотите удалить выбранные события?',
|
||||||
|
'ConfirmDeleteLayout' => 'Вы действительно хотите удалить текущий шаблон?',
|
||||||
'ConfirmPassword' => 'Подтвердите пароль',
|
'ConfirmPassword' => 'Подтвердите пароль',
|
||||||
'ConfirmUnarchiveEvents'=> 'Вы уверены, что хотите удалить из архива выбранные события?',
|
'ConfirmUnarchiveEvents'=> 'Вы уверены, что хотите удалить из архива выбранные события?',
|
||||||
'ConjAnd' => 'и',
|
'ConjAnd' => 'и',
|
||||||
|
|
|
@ -53,7 +53,7 @@ function stringToNumber(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPresetLayout(name) {
|
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() {
|
function getCurrentNameLayout() {
|
||||||
|
@ -137,6 +137,7 @@ function selectLayout(new_layout_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresetLayout(nameLayout)) { //PRESET
|
if (isPresetLayout(nameLayout)) { //PRESET
|
||||||
|
document.getElementById("btnDeleteLayout").setAttribute('disabled', '');
|
||||||
setSelected(document.getElementById("ratio"), getCookie('zmMontageRatioForAll'));
|
setSelected(document.getElementById("ratio"), getCookie('zmMontageRatioForAll'));
|
||||||
changeRatioForAll();
|
changeRatioForAll();
|
||||||
|
|
||||||
|
@ -158,6 +159,7 @@ function selectLayout(new_layout_id) {
|
||||||
}
|
}
|
||||||
initGridStack();
|
initGridStack();
|
||||||
} else { //CUSTOM
|
} else { //CUSTOM
|
||||||
|
document.getElementById("btnDeleteLayout").removeAttribute('disabled');
|
||||||
for (let i = 0, length = monitors.length; i < length; i++) {
|
for (let i = 0, length = monitors.length; i < length; i++) {
|
||||||
const monitor = monitors[i];
|
const monitor = monitors[i];
|
||||||
// Need to clear the current positioning, and apply the new
|
// 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);
|
Positions['monitorRatio'][stringToNumber(this.id)] = getSelected(this);
|
||||||
});
|
});
|
||||||
form.Positions.value = JSON.stringify(Positions, null, ' ');
|
form.Positions.value = JSON.stringify(Positions, null, ' ');
|
||||||
|
$j('#action').attr('value', 'Save');
|
||||||
form.submit();
|
form.submit();
|
||||||
} // end function save_layout
|
} // end function save_layout
|
||||||
|
|
||||||
|
@ -436,6 +439,53 @@ function cancel_layout(button) {
|
||||||
selectLayout();
|
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) {
|
function reloadWebSite(ndx) {
|
||||||
document.getElementById('imageFeed'+ndx).innerHTML = document.getElementById('imageFeed'+ndx).innerHTML;
|
document.getElementById('imageFeed'+ndx).innerHTML = document.getElementById('imageFeed'+ndx).innerHTML;
|
||||||
}
|
}
|
||||||
|
@ -656,9 +706,9 @@ function initPage() {
|
||||||
$j("#flipMontageHeader").slideToggle("fast");
|
$j("#flipMontageHeader").slideToggle("fast");
|
||||||
$j("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
|
$j("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
|
||||||
}
|
}
|
||||||
if (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('#zmMontageLayout').val(getCookie('zmMontageLayout'));
|
||||||
}
|
// }
|
||||||
|
|
||||||
$j(".grid-monitor").hover(
|
$j(".grid-monitor").hover(
|
||||||
//Displaying "Scale" and other buttons at the top of the monitor image
|
//Displaying "Scale" and other buttons at the top of the monitor image
|
||||||
|
|
|
@ -60,6 +60,18 @@ $monitorStatusPositon = array(
|
||||||
|
|
||||||
$monitorStatusPositonSelected = 'outsideImgBottom';
|
$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'])) {
|
if (isset($_REQUEST['monitorStatusPositonSelected'])) {
|
||||||
$monitorStatusPositonSelected = $_REQUEST['monitorStatusPositonSelected'];
|
$monitorStatusPositonSelected = $_REQUEST['monitorStatusPositonSelected'];
|
||||||
} else if (isset($_COOKIE['zmMonitorStatusPositonSelected'])) {
|
} else if (isset($_COOKIE['zmMonitorStatusPositonSelected'])) {
|
||||||
|
@ -69,16 +81,30 @@ if (isset($_REQUEST['monitorStatusPositonSelected'])) {
|
||||||
$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')"));
|
$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')"));
|
||||||
$layoutsById = array();
|
$layoutsById = array();
|
||||||
$FreeFormLayoutId = 0;
|
$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 ) {
|
foreach ( $layouts as $l ) {
|
||||||
if ( $l->Name() == 'Freeform' ) {
|
if ( $l->Name() == 'Freeform' ) {
|
||||||
$FreeFormLayoutId = $l->Id();
|
$FreeFormLayoutId = $l->Id();
|
||||||
$layoutsById[$l->Id()] = $l;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
$layoutsById[$l->Id()] = $l;
|
||||||
foreach ( $layouts as $l ) {
|
|
||||||
if ( $l->Name() != 'Freeform' )
|
|
||||||
$layoutsById[$l->Id()] = $l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zm_session_start();
|
zm_session_start();
|
||||||
|
@ -173,30 +199,20 @@ foreach ($displayMonitors as &$row) {
|
||||||
}
|
}
|
||||||
} # end foreach Monitor
|
} # end foreach Monitor
|
||||||
|
|
||||||
if (!$layout_id) {
|
if (!$layout_id || !is_numeric($layout_id) || !isset($layoutsById[$layout_id])) {
|
||||||
$default_layout = '';
|
$default_layout = '';
|
||||||
if (!$default_layout) {
|
if (count($monitors) > 6) {
|
||||||
if ((count($monitors) > 5) and (count($monitors)%5 == 0)) {
|
$default_layout = '6 Wide';
|
||||||
$default_layout = '5 Wide';
|
} else if (count($monitors) > 4) {
|
||||||
} else if ((count($monitors) > 4) and (count($monitors)%4 == 0)) {
|
$default_layout = '4 Wide';
|
||||||
$default_layout = '4 Wide';
|
} else {
|
||||||
} else if (count($monitors)%3 == 0) {
|
$default_layout = '2 Wide';
|
||||||
$default_layout = '3 Wide';
|
|
||||||
} else {
|
|
||||||
$default_layout = '2 Wide';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($layouts as $l) {
|
|
||||||
if ($l->Name() == $default_layout) {
|
|
||||||
$layout_id = $l->Id();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$layout_id = $arrNameId[$default_layout];
|
||||||
}
|
}
|
||||||
$Layout = '';
|
|
||||||
$Positions = '';
|
|
||||||
if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) {
|
if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) {
|
||||||
$Layout = $layoutsById[$layout_id];
|
|
||||||
$Positions = json_decode($Layout->Positions(), true);
|
|
||||||
} else {
|
} else {
|
||||||
ZM\Debug('Layout not found');
|
ZM\Debug('Layout not found');
|
||||||
}
|
}
|
||||||
|
@ -242,7 +258,7 @@ if (canView('System')) {
|
||||||
<div id="sizeControl">
|
<div id="sizeControl">
|
||||||
<form action="?view=montage" method="post">
|
<form action="?view=montage" method="post">
|
||||||
<input type="hidden" name="object" value="MontageLayout"/>
|
<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">
|
<span id="monitorStatusPositonControl">
|
||||||
<label><?php echo translate('Monitor status position') ?></label>
|
<label><?php echo translate('Monitor status position') ?></label>
|
||||||
|
@ -250,17 +266,17 @@ if (canView('System')) {
|
||||||
</span>
|
</span>
|
||||||
<span id="ratioControl">
|
<span id="ratioControl">
|
||||||
<label><?php echo translate('Ratio') ?></label>
|
<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>
|
||||||
<span id="widthControl" class="hidden">
|
<span id="widthControl" class="hidden"> <!-- OLD version, requires removal -->
|
||||||
<label><?php echo translate('Width') ?></label>
|
<label><?php echo translate('Width') ?></label>
|
||||||
<?php echo htmlSelect('width', $widths, 'auto'/*$options['width']*/, array('id'=>'width', 'data-on-change'=>'changeWidth', 'class'=>'chosen')); ?>
|
<?php echo htmlSelect('width', $widths, 'auto'/*$options['width']*/, array('id'=>'width', 'data-on-change'=>'changeWidth', 'class'=>'chosen')); ?>
|
||||||
</span>
|
</span>
|
||||||
<span id="heightControl" class="hidden">
|
<span id="heightControl" class="hidden"> <!-- OLD version, requires removal -->
|
||||||
<label><?php echo translate('Height') ?></label>
|
<label><?php echo translate('Height') ?></label>
|
||||||
<?php echo htmlSelect('height', $heights, 'auto'/*$options['height']*/, array('id'=>'height', 'data-on-change'=>'changeHeight', 'class'=>'chosen')); ?>
|
<?php echo htmlSelect('height', $heights, 'auto'/*$options['height']*/, array('id'=>'height', 'data-on-change'=>'changeHeight', 'class'=>'chosen')); ?>
|
||||||
</span>
|
</span>
|
||||||
<span id="scaleControl" class="hidden">
|
<span id="scaleControl" class="hidden"> <!-- OLD version, requires removal -->
|
||||||
<label><?php echo translate('Scale') ?></label>
|
<label><?php echo translate('Scale') ?></label>
|
||||||
<?php echo htmlSelect('scale', $scales, '0'/*$scale*/, array('id'=>'scale', 'data-on-change-this'=>'changeScale', 'class'=>'chosen')); ?>
|
<?php echo htmlSelect('scale', $scales, '0'/*$scale*/, array('id'=>'scale', 'data-on-change-this'=>'changeScale', 'class'=>'chosen')); ?>
|
||||||
</span>
|
</span>
|
||||||
|
@ -270,6 +286,7 @@ if (canView('System')) {
|
||||||
</span>
|
</span>
|
||||||
<input type="hidden" name="Positions"/>
|
<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="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;">
|
<span id="SaveLayout" style="display:none;">
|
||||||
<input type="text" name="Name" placeholder="Enter new name for layout if desired" autocomplete="off"/>
|
<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>
|
<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>
|
<script src="<?php echo cache_bust('js/MonitorStream.js') ?>"></script>
|
||||||
<?php xhtmlFooter() ?>
|
<?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 -->
|
<!-- In May 2024, IgorA100 globally changed grid layout -->
|
||||||
<div id="messageModal" class="modal fade" tabindex="-1">
|
<div id="messageModal" class="modal fade" tabindex="-1">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
|
|
Loading…
Reference in New Issue