Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d1e4f73
Feat: Added <select> to control enabling players on Monitor page (mon…
IgorA100 Aug 26, 2025
182360f
Added "ZMSEnabled" (Monitor.php)
IgorA100 Aug 26, 2025
0220604
Disabled the ability to click on the element "input.disabled" (skin.js)
IgorA100 Aug 26, 2025
7f24e0e
Added 'ZMSEnabled' (monitor.php)
IgorA100 Aug 26, 2025
d408688
Added support for "input.disabled" (skin.css)
IgorA100 Aug 26, 2025
b8c9842
Fix Eslint (monitor.js)
IgorA100 Aug 26, 2025
cf0f0a4
Added <select> to select players (monitor.php)
IgorA100 Aug 29, 2025
a5c6e02
Avoid SQL error because we are not using the "ZMSEnabled" field yet(M…
IgorA100 Sep 2, 2025
d218910
Merge branch 'ZoneMinder:master' into patch-439137
IgorA100 Sep 17, 2025
1e336bf
Merge branch 'ZoneMinder:master' into patch-439137
IgorA100 Oct 29, 2025
80c5957
Merge branch 'ZoneMinder:master' into patch-439137
IgorA100 Feb 5, 2026
8d2ca14
Instead of the variable "i," we use "j."Update web/skins/classic/view…
IgorA100 Mar 5, 2026
a012e41
Commented out the unused line 'ZMSEnabled' => 0 (monitor.php)
IgorA100 Mar 8, 2026
ce0974c
event listener to prevent Space/Enter for ".disabled" (web/skins/clas…
IgorA100 Mar 8, 2026
eef799e
Merge branch 'ZoneMinder:master' into patch-439137
IgorA100 Mar 8, 2026
67374da
Use "data-none-exists" instead of the "none-exists" attribute. (monit…
IgorA100 Mar 8, 2026
fbf824e
Use "data-none-exists" instead of the "none-exists" attribute. (web/s…
IgorA100 Mar 8, 2026
658db62
Added the $enableDisableZMS variable, a getter for it, and "construct…
IgorA100 Mar 9, 2026
06bf008
Added the condition "if (ZM\Monitor::getEnableDisableZMS()) $types['Z…
IgorA100 Mar 9, 2026
5c3521d
Added analysis for ZM\Monitor::getEnableDisableZMS() (monitor.php)
IgorA100 Mar 9, 2026
4208fcf
Avoid PHP warnings (monitor.php)
IgorA100 Mar 9, 2026
c1657c7
Merge branch 'ZoneMinder:master' into patch-439137
IgorA100 Mar 30, 2026
5826cd2
Merge branch 'ZoneMinder:master' into patch-439137
IgorA100 Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/includes/Monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ public static function getRTSP2WebStreamOptions() {
'DefaultPlayer' => '',
'RTSP2WebStream' => 'Primary',
'Go2RTCEnabled' => array('type'=>'integer','default'=>0),
//'ZMSEnabled' => array('type'=>'integer','default'=>1),
'JanusEnabled' => array('type'=>'boolean','default'=>0),
'JanusAudioEnabled' => array('type'=>'boolean','default'=>0),
'Janus_Profile_Override' => '',
Expand Down
1 change: 1 addition & 0 deletions web/includes/actions/monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'Enabled' => 0,
'Deleted' => 0,
'DecodingEnabled' => 0,
'ZMSEnabled' => 0,
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZMSEnabled is added here as a checkbox default type, but ZMSEnabled is commented out in Monitor.php's $defaults array (line 234). The Object::changes() method only includes fields that exist in $this->defaults (see web/includes/Object.php:316), so this field will never actually be persisted to the database. Additionally, the ZMSEnabled column doesn't exist in the database schema (it requires a manual ALTER TABLE as mentioned in the PR description). This means the form will submit ZMSEnabled=0 on every save, and the $monitor->changes() call could potentially produce unexpected behavior when it encounters a field that doesn't exist in the monitor object.

Either remove this line (keeping it consistent with the commented-out model definition), or uncomment the model definition and add the corresponding database migration.

Suggested change
'ZMSEnabled' => 0,

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave the line commented out, in case we need to disable ZMS someday.

'RTSP2WebEnabled' => 0,
'Go2RTCEnabled' => 0,
'JanusEnabled' => 0,
Expand Down
20 changes: 14 additions & 6 deletions web/skins/classic/css/base/skin.css
Original file line number Diff line number Diff line change
Expand Up @@ -1261,22 +1261,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) {
Expand Down Expand Up @@ -1332,7 +1339,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'] {
Expand Down
7 changes: 7 additions & 0 deletions web/skins/classic/js/skin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2122,6 +2122,13 @@ function initPageGeneral() {
}
});
});

document.querySelectorAll('input.disabled').forEach(function(el) {
el.addEventListener("click", function clickInputDisabled(event) {
event.preventDefault();
return;
});
});
}

$j( window ).on("load", initPageGeneral);
87 changes: 87 additions & 0 deletions web/skins/classic/views/js/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ function initPage() {
if (!isMobile()) initThumbAnimation();

manageChannelStream();
disableCheckboxesPlayerSelection();
} // end function initPage()

function saveMonitorData(href = '') {
Expand Down Expand Up @@ -840,4 +841,90 @@ 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('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 (var i = 0; i < select.length; i++) {
var option_ = select.options[i];
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);
27 changes: 27 additions & 0 deletions web/skins/classic/views/monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,25 @@ class="nav-link<?php echo ($tab == $name ? ' active' : '') . ' ' . (($name == 'z
break;
}
case 'viewing' :
$selectPlayers = array(
'go2rtc' => 'Go2RTC',
'rtsp2web' => 'RTSP2Web',
'janus' => 'Janus',
'zms' => ['Name' => 'ZMS MJPEG', 'disabled' => 'disabled'],
//'none' => 'None',
);
$selectedPlayers = ['zms'];
//$selectedPlayers = [];
$noneExists = false;
//if ((!$monitor->ZMSEnabled()) && (!$monitor->Go2RTCEnabled()) && (!$monitor->RTSP2WebEnabled()) && (!$monitor->JanusEnabled())) {
//$selectedPlayers[] = 'none';
//$noneExists = true;
//} else {
//if ($monitor->ZMSEnabled()) $selectedPlayers[] = 'zms';
if ($monitor->Go2RTCEnabled()) $selectedPlayers[] = 'go2rtc';
if ($monitor->RTSP2WebEnabled()) $selectedPlayers[] = 'rtsp2web';
if ($monitor->JanusEnabled()) $selectedPlayers[] = 'janus';
//}
?>
<li class="RTSPServer">
<label><?php echo translate('RTSPServer'); echo makeHelpLink('OPTIONS_RTSPSERVER') ?></label>
Expand All @@ -1245,6 +1264,14 @@ class="nav-link<?php echo ($tab == $name ? ' active' : '') . ' ' . (($name == 'z
<label><?php echo translate('RTSPStreamName'); echo makeHelpLink('OPTIONS_RTSPSTREAMNAME') ?></label>
<input type="text" name="newMonitor[RTSPStreamName]" value="<?php echo validHtmlStr($monitor->RTSPStreamName()) ?>"/>
</li>
<li id="SelectPlayers" class="SelectPlayers">
<label><?php echo translate('Select players'); echo makeHelpLink('OPTIONS_SELECTPLAYERS') ?> </label>
<?php echo htmlSelect('SelectPlayers', $selectPlayers, $selectedPlayers, ['class'=>'chosen chosen-full-width', 'multiple'=>'', 'data-on-change'=>'selectPlayers', 'none-exists'=>$noneExists]); ?>
</li>
<!--<li id="FunctionZMSEnabled" class='hidden-shift'>
<label><?php //echo translate('ZMS MJPEG') ?></label>
<input type="checkbox" name="newMonitor[ZMSEnabled]" value="1"<?php //echo $monitor->ZMSEnabled() ? ' checked="checked"' : '' ?> class="hidden-shift0"/>
</li>-->
<li id="FunctionGo2RTCEnabled">
<label><?php echo translate('Go2RTC Live Stream') ?></label>
<input type="checkbox" name="newMonitor[Go2RTCEnabled]" value="1"<?php echo $monitor->Go2RTCEnabled() ? ' checked="checked"' : '' ?> on_click="update_players"/>
Expand Down
Loading