From 634d718359cbdd08311556f832ab075766edecfe Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Fri, 23 Aug 2024 23:40:44 +0300 Subject: [PATCH 001/265] ".sticky #mfbpanel" height no more than 40% of the screen (skin.css) Relevant for mobile devices. --- web/skins/classic/css/base/skin.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index dff9f6f51..454a3b7fc 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -779,6 +779,11 @@ ul.nav.nav-pills.flex-column { float: left; } +.sticky #mfbpanel { + max-height: 40vh; /* For mobile devices */ + overflow: auto; +} + .chosen { position: absolute !important; left: -999em !important; } From edf7f808b0073ac3744078e464f7113e8e8a3bf8 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Wed, 18 Sep 2024 12:23:33 +0300 Subject: [PATCH 002/265] Fix: Panning didn't work when using "preventDefault" (panzoom.js) This happened after PR #4137 When Scale panZoom > 1, you need to use "preventDefault" for Panning to work correctly. But at the same time (if Scale panZoom > 1), clicking on the progress bar generated by video.js will not work. In principle, this is not critical, because when increasing, the progress bar generated by video.js usually goes beyond the visible boundaries. --- web/js/panzoom.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/js/panzoom.js b/web/js/panzoom.js index 1bb668077..32870f427 100644 --- a/web/js/panzoom.js +++ b/web/js/panzoom.js @@ -251,6 +251,12 @@ var zmPanZoom = { } } } + + if (this.panZoom[id].getScale().toFixed(1) > 1) { + this.panZoom[id].setOptions({handleStartEvent: (event) => {event.preventDefault()}}); + } else { + this.panZoom[id].setOptions({handleStartEvent: (event) => {}}); + } }, click: function(id) { From 52a5bf2a1f4df7f004a1821354626c97dbdd5c68 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Wed, 18 Sep 2024 12:30:04 +0300 Subject: [PATCH 003/265] Chore: Eslint (panzoom.js) --- web/js/panzoom.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/js/panzoom.js b/web/js/panzoom.js index 32870f427..181ec4466 100644 --- a/web/js/panzoom.js +++ b/web/js/panzoom.js @@ -253,7 +253,9 @@ var zmPanZoom = { } if (this.panZoom[id].getScale().toFixed(1) > 1) { - this.panZoom[id].setOptions({handleStartEvent: (event) => {event.preventDefault()}}); + this.panZoom[id].setOptions({handleStartEvent: (event) => { + event.preventDefault(); + }}); } else { this.panZoom[id].setOptions({handleStartEvent: (event) => {}}); } From 6feffbaefaf00d4b5ff21e8ed39c51178b425344 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Wed, 18 Sep 2024 13:34:18 +0300 Subject: [PATCH 004/265] Max height limit for .sticky #toolbar & .sticky #mfbpanel (skin.css) --- web/skins/classic/css/base/skin.css | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index 454a3b7fc..e8a9fb8c7 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -776,12 +776,7 @@ ul.nav.nav-pills.flex-column { #mfbpanel { width: calc(100% - 25px); - float: left; -} - -.sticky #mfbpanel { - max-height: 40vh; /* For mobile devices */ - overflow: auto; + float: left; } .chosen { @@ -1123,6 +1118,19 @@ html::-webkit-scrollbar-thumb, div::-webkit-scrollbar-thumb, nav::-webkit-scroll } } +@media screen and (max-height:600px) { + .sticky #mfbpanel { + max-height: 40vh; /* For mobile devices */ + overflow-y: auto; + overflow-x: hidden; + } + + .sticky #toolbar { + max-height: 20vh; /* For mobile devices */ + overflow-y: auto; + overflow-x: hidden; + } +} /* +++ This block should always be located at the end! */ .hidden { display: none; From 0f37a71338401478ad7cd436fa160779a2b780c1 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Wed, 18 Sep 2024 13:35:49 +0300 Subject: [PATCH 005/265] Removed redundant comments (skin.css) --- web/skins/classic/css/base/skin.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index e8a9fb8c7..231f9db91 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -1120,13 +1120,13 @@ html::-webkit-scrollbar-thumb, div::-webkit-scrollbar-thumb, nav::-webkit-scroll @media screen and (max-height:600px) { .sticky #mfbpanel { - max-height: 40vh; /* For mobile devices */ + max-height: 40vh; overflow-y: auto; overflow-x: hidden; } .sticky #toolbar { - max-height: 20vh; /* For mobile devices */ + max-height: 20vh; overflow-y: auto; overflow-x: hidden; } From 334d84042518815f10416e664230fd4b64c16b97 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Wed, 18 Sep 2024 15:04:40 +0300 Subject: [PATCH 006/265] Restored accidentally deleted block (skin.css) --- web/skins/classic/css/base/skin.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index aa7a0e5f0..8574054e0 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -1201,6 +1201,12 @@ button.btn.btn-edit-monitor:hover, button.btn.btn-view-watch:hover { background-color: darkgrey; } + +.controlHeader .chosen-container { + /* limit width of monitor filters so that it fits on 1920px */ + max-width: 300px; +} + /* --- Control button block in the Stream image*/ /* +++ This block should always be located at the end! */ From 3dd08cd2134c466fbbd3a7a6b7b4a76de062610c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Sep 2024 16:09:38 -0400 Subject: [PATCH 007/265] Load duration from the db instead of calculating it from start and endtime. This gives us the decimal part as well. --- src/zm_eventstream.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 4ff996509..b6ebe4e66 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -112,7 +112,7 @@ bool EventStream::loadInitialEventData( bool EventStream::loadEventData(uint64_t event_id) { std::string sql = stringtf( "SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartDateTime` ) AS StartTimestamp, " - "unix_timestamp( `EndDateTime` ) AS EndTimestamp, " + "unix_timestamp( `EndDateTime` ) AS EndTimestamp, Length, " "(SELECT max(`Delta`)-min(`Delta`) FROM `Frames` WHERE `EventId`=`Events`.`Id`) AS FramesDuration, " "`DefaultVideo`, `Scheme`, `SaveJPEGs`, `Orientation`+0 FROM `Events` WHERE `Id` = %" PRIu64, event_id); @@ -140,11 +140,11 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]); event_data->start_time = SystemTimePoint(Seconds(atoi(dbrow[3]))); event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : std::chrono::system_clock::now(); - event_data->duration = std::chrono::duration_cast(event_data->end_time - event_data->start_time); + event_data->duration = std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : event_data->end_time - event_data->start_time); event_data->frames_duration = - std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); - event_data->video_file = std::string(dbrow[6]); - std::string scheme_str = std::string(dbrow[7]); + std::chrono::duration_cast(dbrow[6] ? FPSeconds(atof(dbrow[6])) : FPSeconds(0.0)); + event_data->video_file = std::string(dbrow[7]); + std::string scheme_str = std::string(dbrow[8]); if ( scheme_str == "Deep" ) { event_data->scheme = Storage::DEEP; } else if ( scheme_str == "Medium" ) { @@ -152,8 +152,8 @@ bool EventStream::loadEventData(uint64_t event_id) { } else { event_data->scheme = Storage::SHALLOW; } - event_data->SaveJPEGs = dbrow[8] == nullptr ? 0 : atoi(dbrow[8]); - event_data->Orientation = (Monitor::Orientation)(dbrow[9] == nullptr ? 0 : atoi(dbrow[9])); + event_data->SaveJPEGs = dbrow[9] == nullptr ? 0 : atoi(dbrow[9]); + event_data->Orientation = (Monitor::Orientation)(dbrow[10] == nullptr ? 0 : atoi(dbrow[10])); mysql_free_result(result); if (!monitor) { @@ -654,7 +654,7 @@ void EventStream::processCommand(const CmdMsg *msg) { status_data.event_id = event_data->event_id; //status_data.duration = event_data->duration; - status_data.duration = std::chrono::duration(event_data->duration).count(); + status_data.duration = FPSeconds(event_data->duration).count(); //status_data.progress = event_data->frames[curr_frame_id-1].offset; status_data.progress = std::chrono::duration(event_data->frames[curr_frame_id-1].offset).count(); status_data.rate = replay_rate; From 05554757bc58bc82331f01e0e909256464513f7e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Sep 2024 17:43:17 -0400 Subject: [PATCH 008/265] Don't use a define for MAX_PRESETS so that we can include control_functions multiple times --- web/skins/classic/includes/control_functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index 9f434872b..ba79e45b9 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -149,7 +149,7 @@ function controlPanTilt($monitor, $cmds) { function controlPresets($monitor, $cmds) { $control = $monitor->Control(); // MAX_PRESETS IS PER LINE - define('MAX_PRESETS', '12'); + $max_presets = 12; $sql = 'SELECT * FROM ControlPresets WHERE MonitorId = ?'; $labels = array(); @@ -157,7 +157,7 @@ function controlPresets($monitor, $cmds) { $labels[$row['Preset']] = $row['Label']; } - $presetBreak = (int)(($control->NumPresets()+1)/((int)(($control->NumPresets()-1)/MAX_PRESETS)+1)); + $presetBreak = (int)(($control->NumPresets()+1)/((int)(($control->NumPresets()-1)/$max_presets)+1)); ob_start(); ?> From 6d7ee93fc3d7288978ef5f24e93411ba8b3e00d8 Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Fri, 20 Sep 2024 17:21:51 +0300 Subject: [PATCH 009/265] Fix: The double click to go fullscreen should only happen if not shift/ctl modifiers are active (skin.js) Close #4141 --- web/skins/classic/js/skin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 6cd29a78f..2a4868aaa 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -1227,6 +1227,7 @@ var doubleTouchExecute = function(event, touchEvent) { }; var doubleClickOnStream = function(event, touchEvent) { + if (shifted || ctrled || alted) return; let target = null; if (event.target) {// Click NOT on touch screen, use THIS //Process only double clicks directly on the image, excluding clicks, From b5cec409553fdf86964d4e5eab2cf35e0f0487b7 Mon Sep 17 00:00:00 2001 From: Simpler1 Date: Fri, 20 Sep 2024 15:43:27 -0400 Subject: [PATCH 010/265] Fix(events): Remember column visibility changes --- web/skins/classic/views/events.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 0a18db37d..1bfe117a5 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -153,7 +153,6 @@ getBodyTopHTML(); data-buttons-class="btn btn-normal" data-show-jump-to="true" data-show-refresh="true" - data-columns-hidden="['Archived','Emailed','Monitor','Id','Name'.'Frames','AlarmFrames','TotScore','AvgScore']" data-check-on-init="true" data-mobile-responsive="true" data-min-width="562" From d05cccb2dddd281d284b2b02d6b73cd64a4f6c33 Mon Sep 17 00:00:00 2001 From: Simpler1 Date: Fri, 20 Sep 2024 16:13:15 -0400 Subject: [PATCH 011/265] fix(events): Initial hidden columns when cookie doesn't exist The name of the cookie is zmEventsTable.bs.table.hiddenColumns not zmEventsTable.bs.table.columns --- web/skins/classic/views/js/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 6c553e995..52a00c9d6 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -311,7 +311,7 @@ function initPage() { table.bootstrapTable({icons: icons}); // Hide these columns on first run when no cookie is saved - if (!getCookie('zmEventsTable.bs.table.columns')) { + if (!getCookie('zmEventsTable.bs.table.hiddenColumns')) { // table.bootstrapTable('hideColumn', 'Archived'); table.bootstrapTable('hideColumn', 'Emailed'); } From 312a15801e8f009b4d1ba65e306c40366cdee4e8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Sep 2024 18:54:54 -0400 Subject: [PATCH 012/265] Using last_delta really doesn't work. Instead let's use remaining time/remaining frames. --- src/zm_eventstream.cpp | 59 +++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 4ff996509..351669838 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -290,11 +290,10 @@ bool EventStream::loadEventData(uint64_t event_id) { } // end foreach db row if (event_data->end_time.time_since_epoch() != Seconds(0)) { - Microseconds delta = (last_frame && (last_frame->delta > Microseconds(0))) - ? last_frame->delta - : Microseconds( static_cast(1000000 * base_fps / FPSeconds(event_data->duration).count()) ); + Microseconds delta; if (!last_frame) { // There were no frames in db + delta = Microseconds( static_cast(1000000 * base_fps / FPSeconds(event_data->duration).count()) ); auto frame = event_data->frames.emplace_back( 1, event_data->start_time, @@ -306,28 +305,38 @@ bool EventStream::loadEventData(uint64_t event_id) { last_id ++; last_timestamp = event_data->start_time; event_data->frame_count ++; + } else { + delta = std::chrono::duration_cast((event_data->end_time - last_timestamp)/(event_data->frame_count-last_id)); + Debug(1, "Setting delta from endtime %f - %f / %d - %d", + FPSeconds(event_data->end_time.time_since_epoch()).count(), + FPSeconds(last_timestamp.time_since_epoch()).count(), + event_data->frame_count, + last_id + ); } - while (event_data->end_time > last_timestamp and !zm_terminate) { - last_timestamp += delta; - last_id ++; + if (delta > Microseconds(0)) { + while (event_data->end_time > last_timestamp and !zm_terminate) { + last_timestamp += delta; + last_id ++; - auto frame = event_data->frames.emplace_back( - last_id, - last_timestamp, - last_frame->offset + delta, - delta, - false - ); - last_frame = &frame; - Debug(3, "Trailing Frame %d timestamp (%f s), offset (%f s), delta(%f s), in_db(%d)", - last_id, - FPSeconds(frame.timestamp.time_since_epoch()).count(), - FPSeconds(frame.offset).count(), - FPSeconds(frame.delta).count(), - frame.in_db); - event_data->frame_count ++; - } // end while + auto frame = event_data->frames.emplace_back( + last_id, + last_timestamp, + last_frame->offset + delta, + delta, + false + ); + last_frame = &frame; + Debug(3, "Trailing Frame %d timestamp (%f s), offset (%f s), delta(%f s), in_db(%d)", + last_id, + FPSeconds(frame.timestamp.time_since_epoch()).count(), + FPSeconds(frame.offset).count(), + FPSeconds(frame.delta).count(), + frame.in_db); + event_data->frame_count ++; + } // end while + } } // end if have endtime // Incomplete events might not have any frame data @@ -339,11 +348,7 @@ bool EventStream::loadEventData(uint64_t event_id) { } mysql_free_result(result); - if (!event_data->video_file.empty() || (monitor->GetOptVideoWriter() > 0)) { - if (event_data->video_file.empty()) { - event_data->video_file = stringtf("%" PRIu64 "-%s", event_data->event_id, "video.mp4"); - } - + if (!event_data->video_file.empty()) { std::string filepath = event_data->path + "/" + event_data->video_file; Debug(1, "Loading video file from %s", filepath.c_str()); delete ffmpeg_input; From 852af8ee982fdb4734022941c63c66891f9e3b25 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Sep 2024 09:42:31 -0400 Subject: [PATCH 013/265] Code cleanups, apply use strict, comments, update event title when switching events. --- web/skins/classic/views/js/event.js | 45 +++++++++++++++-------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index c2c98ae37..a9fdc252f 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -1,3 +1,4 @@ +"use strict"; var eventStats = $j('#eventStats'); var eventVideo = $j('#eventVideo'); var wrapperEventVideo = $j('#wrapperEventVideo'); @@ -172,7 +173,7 @@ function setAlarmCues(data) { Error('No data.frames in setAlarmCues for event ' + eventData.Id); } else { cueFrames = data.frames; - alarmSpans = renderAlarmCues(vid ? $j("#videoobj") : $j("#evtStream"));//use videojs width or zms width + const alarmSpans = renderAlarmCues(vid ? $j("#videoobj") : $j("#evtStream"));//use videojs width or zms width $j('#alarmCues').html(alarmSpans); } } @@ -180,7 +181,6 @@ function setAlarmCues(data) { function renderAlarmCues(containerEl) { let html = ''; - cues_div = document.getElementById('alarmCues'); const event_length = (!cueFrames.length || (eventData.Length > cueFrames[cueFrames.length - 1].Delta)) ? eventData.Length : cueFrames[cueFrames.length - 1].Delta; const span_count = 10; const span_seconds = parseFloat(event_length / span_count); @@ -210,7 +210,7 @@ function renderAlarmCues(containerEl) { for (let i=0; i < num_cueFrames; i++) { skip = 0; - frame = cueFrames[i]; + const frame = cueFrames[i]; if ((frame.Type == 'Alarm') && (alarmed == 0)) { //From nothing to alarm. End nothing and start alarm. alarmed = 1; @@ -257,7 +257,7 @@ function renderAlarmCues(containerEl) { pix += Math.round(pixSkew); pixSkew = pixSkew - Math.round(pixSkew); } - alarmHtml += ''; + alarmHtml += ''; left = parseInt((frame.Delta / event_length) * containerEl.width()); spanTimeStart = spanTimeEnd; } else if ( (frame.Type == 'Alarm') && (alarmed == 1) && (i + 1 >= cueFrames.length) ) { //event ends on an alarm @@ -267,7 +267,7 @@ function renderAlarmCues(containerEl) { pix = Math.round(cueRatio * spanTime); if (pixSkew >= .5 || pixSkew <= -.5) pix += Math.round(pixSkew); - alarmHtml += ''; + alarmHtml += ''; } } return html + alarmHtml; @@ -330,7 +330,7 @@ function changeScale() { currentScale = currentScale; } - //console.log(`Real dimensions: ${eventData.Width} X ${eventData.Height}, Scale: ${currentScale}, deltaScale: ${deltaScale()}, New dimensions: ${newWidth} X ${newHeight}`); + console.log(`Real dimensions: ${eventData.Width} X ${eventData.Height}, Scale: ${currentScale}, deltaScale: ${deltaScale()}, New dimensions: ${newWidth} X ${newHeight}`); eventViewer.width(newWidth); eventViewer.height(newHeight); @@ -393,15 +393,14 @@ function changeStreamQuality() { } function changeReplayMode() { - var replayMode = $j('#replayMode').val(); - + const replayMode = $j('#replayMode').val(); setCookie('replayMode', replayMode); - + // FIXME don't need to refresh, can just tell zms refreshWindow(); } function changeRate() { - var rate = parseInt($j('select[name="rate"]').val()); + const rate = parseInt($j('select[name="rate"]').val()); if (!rate) { pauseClicked(); @@ -470,11 +469,11 @@ function getCmdResponse(respObj, respText) { } if (streamStatus.paused == true) { - streamPause( ); + streamPause(); } else { $j('select[name="rate"]').val(streamStatus.rate*100); setCookie('zmEventRate', streamStatus.rate*100); - streamPlay( ); + streamPlay(); } $j('#progressValue').html(secsToTime(parseInt(streamStatus.progress))); //$j('#zoomValue').html(streamStatus.zoom); @@ -486,7 +485,7 @@ function getCmdResponse(respObj, respText) { //} if (currentScale && (streamStatus.scale !== undefined) && (streamStatus.scale != currentScale + deltaScale())) { - console.log("Stream not scaled, re-applying", currentScale + deltaScale(), streamStatus.scale); + console.log("Stream not scaled, re-applying, current: ", currentScale + deltaScale(), " stream: ", streamStatus.scale); streamScale(currentScale); } @@ -494,7 +493,7 @@ function getCmdResponse(respObj, respText) { if (streamStatus.auth) { auth_hash = streamStatus.auth; - } // end if haev a new auth hash + } // end if have a new auth hash streamCmdTimer = setTimeout(streamQuery, streamTimeout); //Timeout is refresh rate for progressBox and time display } // end function getCmdResponse( respObj, respText ) @@ -528,7 +527,7 @@ function playClicked( ) { const rate_select = $j('select[name="rate"]'); if (!rate_select.val()) { - $j('select[name="rate"]').val(100); + rate_select.val(100); } if (vid) { if (vid.paused()) { @@ -680,18 +679,20 @@ function streamNext(action) { $j(".vjsMessage").remove();//This shouldn't happen if (nextEventId == 0) { //handles deleting last event. pauseClicked(); - var hideContainer = $j('#eventVideo'); - var hideStream = $j(vid ? "#videoobj" : "#evtStream").height() + (vid ? 0 :$j("#progressBar").height()); + const hideContainer = $j('#eventVideo'); + const hideStream = $j(vid ? "#videoobj" : "#evtStream").height() + (vid ? 0 :$j("#progressBar").height()); hideContainer.prepend('

No more events

'); if (vid == null) zmsBroke = true; return; } // We used to try to dynamically update all the bits in the page, which is really complex // How about we just reload the page? - // - if (vid==null) streamReq({command: CMD_QUIT}); - location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery); - return; + // Ic0n 2024-09-20: because it is annoying and now that we have fullscreen mode, we need to just update instead of reloading + if (1) { + if (vid==null) streamReq({command: CMD_QUIT}); + location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery); + return; + } if (vid && ( NextEventDefVideoPath.indexOf('view_video') > 0 )) { // on and staying with videojs CurEventDefVideoPath = NextEventDefVideoPath; @@ -701,6 +702,7 @@ function streamNext(action) { (vid && NextEventDefVideoPath.indexOf("view_video") < 0) || NextEventDefVideoPath.indexOf("view_video") > 0 ) {//reload zms, leaving vjs, moving to vjs + // Need to be able to replace video.js with zms or vice versa as required instead of reloading location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery); } else { streamReq({command: CMD_NEXT}); @@ -831,6 +833,7 @@ function getEventResponse(respObj, respText) { eventData = respObj.event; getStat(); currEventId = eventData.Id; + $j('#eventTitle').html('Event '+currEventId); // FIXME should translate Event // Refresh the status of the archive buttons archiveBtn.prop('disabled', !(!eventData.Archived && canEdit.Events)); From 2f013e0443322bc01ba9880c16fbab4b3196a5da Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Sep 2024 09:42:44 -0400 Subject: [PATCH 014/265] GIve event title an id, so we can update it --- web/skins/classic/views/event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 4779b439a..1f05edb14 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -226,7 +226,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) ) ?> -

Id() ?>

+

Id() ?>

From 42edacbc6bc4c20bf2f25e112a6f596af10141fd Mon Sep 17 00:00:00 2001 From: IgorA100 Date: Sat, 21 Sep 2024 20:46:45 +0300 Subject: [PATCH 015/265] Fix: Support STICKY mode for isOutOfViewport (montage.js) --- web/skins/classic/views/js/montage.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 592e557f2..0f74fb08d 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -855,13 +855,14 @@ function on_scroll() { function isOutOfViewport(elem) { // Get element's bounding const bounding = elem.getBoundingClientRect(); + const headerHeight = (parseInt(ZM_WEB_NAVBAR_STICKY) == 1) ? document.getElementById('navbar-container').offsetHeight + document.getElementById('header').offsetHeight : 0; //console.log( 'top: ' + bounding.top + ' left: ' + bounding.left + ' bottom: '+bounding.bottom + ' right: '+bounding.right); // Check if it's out of the viewport on each side const out = {}; - out.top = (bounding.top < 0) || ( bounding.top > (window.innerHeight || document.documentElement.clientHeight) ); + out.top = (bounding.top < headerHeight) || ( bounding.top > (window.innerHeight || document.documentElement.clientHeight) ); out.left = (bounding.left < 0) || (bounding.left > (window.innerWidth || document.documentElement.clientWidth)); - out.bottom = (bounding.bottom > (window.innerHeight || document.documentElement.clientHeight) ) || (bounding.bottom < 0); + out.bottom = (bounding.bottom > (window.innerHeight-headerHeight || document.documentElement.clientHeight-headerHeight) ) || (bounding.bottom < 0); out.right = (bounding.right > (window.innerWidth || document.documentElement.clientWidth) ) || (bounding.right < 0); out.any = out.top || out.left || out.bottom || out.right; out.all = (out.top && out.bottom ) || (out.left && out.right); From ea1fd087802ba3da863e08997914dbf3deb325a2 Mon Sep 17 00:00:00 2001 From: unbroken75 Date: Sun, 22 Sep 2024 16:15:27 +0200 Subject: [PATCH 016/265] Update debian.rst --- docs/installationguide/debian.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index 082ee2b2b..64da98ca1 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -200,9 +200,11 @@ To make sure zoneminder can read the configuration file, run the following comma :: sudo a2enconf zoneminder + sudo a2enmod cgi sudo systemctl reload apache2.service sudo systemctl restart zoneminder.service sudo systemctl status zoneminder.service + sudo systemctl enable zoneminder.service # start zoneminder automatically at boot If the zoneminder.service show to be active and without any errors, you should be able to access zoneminder at ``http://yourhostname/zm`` From 6a672c4627906191732dccf3dea77e8a87b7f680 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 22 Sep 2024 10:57:39 -0400 Subject: [PATCH 017/265] Height will always be true to do px being appended. Leave it as number until setting height. --- web/skins/classic/views/js/montage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 0f74fb08d..5248de103 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -368,12 +368,12 @@ function setRatioForMonitor(objStream, id=null) { ratio = (value == 'auto') ? averageMonitorsRatio : partsRatio[0]/partsRatio[1]; } - const height = (currentMonitor.width / currentMonitor.height > 1) ? (objStream.clientWidth / ratio + 'px') /* landscape */ : (objStream.clientWidth * ratio + 'px'); + const height = (currentMonitor.width / currentMonitor.height > 1) ? (objStream.clientWidth / ratio) /* landscape */ : (objStream.clientWidth * ratio); if (!height) { console.log("0 height from ", currentMonitor.width, currentMonitor.height, (currentMonitor.width / currentMonitor.height > 1), objStream.clientWidth / ratio); } else { - objStream.style['height'] = height; - objStream.parentNode.style['height'] = height; + objStream.style['height'] = height + 'px'; + objStream.parentNode.style['height'] = height + 'px'; } } From da4636d11d076e9bbf4460a10eee3cfc148b8108 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 22 Sep 2024 11:13:04 -0400 Subject: [PATCH 018/265] Make clean button always visible --- web/skins/classic/views/console.php | 4 +--- web/skins/classic/views/js/console.js | 12 ++++-------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 2718cc5d5..7580bc888 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -201,9 +201,7 @@ echo $navbar ?> add_circle   -