diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 6f9c05cfb2..a041657432 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -14,6 +14,19 @@ class Monitor extends ZM_Object { private $shm_id = null; private $connected = false; + private static $enableDisableZMS = false; // This setting is for future use, in case we decide to disable ALL players, including ZMS. + // To be able to disable/enable the ZMS player, you need to run the following code in the database: + // "ALTER TABLE `Monitors` ADD COLUMN `ZMSEnabled` BOOLEAN NOT NULL default true AFTER `Decoding`" + + public function __construct($IdOrRow = NULL) { + parent::__construct($IdOrRow); + if (self::$enableDisableZMS) $this->defaults['ZMSEnabled'] = array('type'=>'integer','default'=>1); + } + + public static function getEnableDisableZMS() { + return self::$enableDisableZMS; + } + private $shm_offsets = ['SharedData' => [ 'size' => [ 'type'=>'uint32', 'offset'=>0, 'size'=>4 ], 'last_write_index' => [ 'type'=>'int32', 'offset'=>4, 'size'=>4 ], diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 0ef133d413..0a8a1a87b1 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -126,6 +126,7 @@ 'SectionLengthWarn' => 0, 'SOAP_wsa_compl' => 0 ); + if (ZM\Monitor::getEnableDisableZMS()) $types['ZMSEnabled'] = 0; # Checkboxes don't return an element in the POST data, so won't be present in newMonitor. # So force a value for these fields diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index c93aac9740..361262f805 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -1395,22 +1395,29 @@ button.btn.btn-view-watch:hover { --d-t: 0.6s; --d-t-e: cubic-bezier(0.2, 0.85, 0.32, 1.2); } - input[type='checkbox']:disabled, input[type='radio']:disabled { + input[type='checkbox'].disabled:not(.input-switch):after { + border-color: var(--active); + } + input[type='checkbox']:disabled, input[type='radio']:disabled, + input[type='checkbox'].disabled, input[type='radio'].disabled { --b: var(--disabled); cursor: not-allowed; opacity: 0.9; } - input[type='checkbox']:disabled:checked, input[type='radio']:disabled:checked { + input[type='checkbox']:disabled:checked, input[type='radio']:disabled:checked, + input[type='checkbox'].disabled:checked, input[type='radio'].disabled:checked { --b: var(--disabled-inner); --bc: var(--border); } - input[type='checkbox']:disabled + label, input[type='radio']:disabled + label { + input[type='checkbox']:disabled + label, input[type='radio']:disabled + label, + input[type='checkbox'].disabled + label, input[type='radio'].disabled + label { cursor: not-allowed; } - input[type='checkbox']:hover:not(:checked):not(:disabled), input[type='radio']:hover:not(:checked):not(:disabled) { + input[type='checkbox']:hover:not(:checked):not(:disabled), input[type='radio']:hover:not(:checked):not(:disabled), + input[type='checkbox']:hover:not(:checked):not(.disabled), input[type='radio']:hover:not(:checked):not(.disabled) { --bc: var(--border-hover); } - input[type='checkbox']:focus, input[type='radio']:focus { + input[type='checkbox']:not(.disabled):focus, input[type='radio']:not(.disabled):focus { box-shadow: 0 0 0 var(--focus); } input[type='checkbox']:not(.input-switch), input[type='radio']:not(.input-switch) { @@ -1466,7 +1473,8 @@ button.btn.btn-view-watch:hover { --ab: var(--active-inner); --x: 17px; } - input[type='checkbox'].input-switch:disabled:not(:checked):after { + input[type='checkbox'].input-switch:disabled:not(:checked):after, + input[type='checkbox'].input-switch.disabled:not(:checked):after { opacity: 0.6; } input[type='radio'] { diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index af9a4613ab..df19706fc1 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -2595,6 +2595,20 @@ function initPageGeneral() { } }); }); + + document.querySelectorAll('input.disabled').forEach(function(el) { + el.addEventListener("click", function clickInputDisabled(event) { + event.preventDefault(); + return; + }); + el.addEventListener("keydown", function keydownInputDisabled(event) { + var key = event.key || event.keyCode; + if (key === ' ' || key === 'Spacebar' || key === 'Enter' || key === 32 || key === 13) { + event.preventDefault(); + event.stopPropagation(); + } + }); + }); } // Called when monitor filters change - refreshes table via AJAX instead of full page reload diff --git a/web/skins/classic/views/js/monitor.js b/web/skins/classic/views/js/monitor.js index 006a4475c9..b06d5ca8a9 100644 --- a/web/skins/classic/views/js/monitor.js +++ b/web/skins/classic/views/js/monitor.js @@ -525,6 +525,7 @@ function initPage() { if (!isMobile()) initThumbAnimation(); manageChannelStream(); + disableCheckboxesPlayerSelection(); } // end function initPage() function saveMonitorData(href = '') { @@ -896,6 +897,92 @@ function ControlList_onClick() { window.location = '?view=options&tab=control'; } +function selectPlayersSetZMS(select) { + for (var i = 0; i < select.length; i++) { + var option_ = select.options[i]; + if (option_.value == 'zms') { + option_.selected = true; + break; + } + } + selectPlayersChangeCheckBox('zms', 'set'); +} + +function disableCheckboxesPlayerSelection() { + // Now all control is via multi selector #SelectPlayers + let checkBox; + checkBox = document.querySelector('input[name="newMonitor[ZMSEnabled]"]'); + if (checkBox) checkBox.classList.add('disabled'); + + checkBox = document.querySelector('input[name="newMonitor[Go2RTCEnabled]"]'); + if (checkBox) checkBox.classList.add('disabled'); + + checkBox = document.querySelector('input[name="newMonitor[RTSP2WebEnabled]"]'); + if (checkBox) checkBox.classList.add('disabled'); + + checkBox = document.querySelector('input[name="newMonitor[JanusEnabled]"]'); + if (checkBox) checkBox.classList.add('disabled'); + + const sel = document.querySelector('select[name="SelectPlayers"]'); + if (sel) sel.noneExists = sel.getAttribute('data-none-exists'); +} + +function selectPlayersChangeCheckBox(selectedPlayer, action) { + let checkBox; + if (selectedPlayer == 'zms') { + checkBox = document.querySelector('input[name="newMonitor[ZMSEnabled]"]'); + } else if (selectedPlayer == 'go2rtc') { + checkBox = document.querySelector('input[name="newMonitor[Go2RTCEnabled]"]'); + } else if (selectedPlayer == 'rtsp2web') { + checkBox = document.querySelector('input[name="newMonitor[RTSP2WebEnabled]"]'); + } else if (selectedPlayer == 'janus') { + checkBox = document.querySelector('input[name="newMonitor[JanusEnabled]"]'); + } + if (checkBox) { + checkBox.checked = (action == 'set') ? true : false; + // Need to call the "change" event trigger + const event = new Event("change"); + checkBox.dispatchEvent(event); + } +} + +function selectPlayers(e) { + var select = e.target; + var count = 0; + for (var i = 0; i < select.length; i++) { + var option = select.options[i]; + if (option.selected) { + count++; + if (option.value == 'none') { + if (select.noneExists) { //Previously 'none' was already added, and now we are changing something + select.noneExists = false; + option.selected = false; + selectPlayersSetZMS(select); + } else { //Adding for the first time + select.noneExists = true; + for (let j = 0; j < select.length; j++) { + var option_ = select.options[j]; + if (option_.value != 'none') { + option_.selected = false; + selectPlayersChangeCheckBox(option_.value, 'remove'); + //option_.removeAttribute('selected'); + } + } + } + } else { //Let's set a checkbox for the corresponding player + selectPlayersChangeCheckBox(option.value, 'set'); + } + } else { //Let's reset the checkbox for the corresponding player + selectPlayersChangeCheckBox(option.value, 'remove'); + } + } + if (count === 0) { + select.noneExists = false; + selectPlayersSetZMS(select); + } + applyChosen(); +} + window.addEventListener('DOMContentLoaded', initPage); // Clear password field values when navigating away from the page so diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index ca7b7ac09b..13a9e4e65d 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -1248,6 +1248,24 @@ class="nav-link 'Go2RTC', + 'rtsp2web' => 'RTSP2Web', + 'janus' => 'Janus', + 'zms' => ['Name' => 'ZMS MJPEG', 'disabled' => 'disabled'], + ); + if (ZM\Monitor::getEnableDisableZMS()) $selectPlayers = array_merge($selectPlayers, array('none' => 'None')); // Add an option to disable all players + $selectedPlayers = []; + $noneExists = false; // All players are disabled + if ((ZM\Monitor::getEnableDisableZMS() && !$monitor->ZMSEnabled()) && (!$monitor->Go2RTCEnabled()) && (!$monitor->RTSP2WebEnabled()) && (!$monitor->JanusEnabled())) { + $selectedPlayers[] = 'none'; + $noneExists = true; + } else { + if (!ZM\Monitor::getEnableDisableZMS() || (ZM\Monitor::getEnableDisableZMS() && $monitor->ZMSEnabled())) $selectedPlayers[] = 'zms'; + if ($monitor->Go2RTCEnabled()) $selectedPlayers[] = 'go2rtc'; + if ($monitor->RTSP2WebEnabled()) $selectedPlayers[] = 'rtsp2web'; + if ($monitor->JanusEnabled()) $selectedPlayers[] = 'janus'; + } ?>
  • @@ -1257,6 +1275,22 @@ class="nav-link
  • +
  • + + 'chosen chosen-full-width', 'multiple'=>'', 'data-on-change'=>'selectPlayers', 'data-none-exists'=>$noneExists]); ?> +
  • +ZMSEnabled()) ? ' checked="checked"' : ''; + $strZMSEnabled = ' +
  • + + +
  • + '; + echo $strZMSEnabled; +} +?>
  • Go2RTCEnabled() ? ' checked="checked"' : '' ?> on_click="update_players"/>