From c6373d3dcaa73d0e261aceb6c97320ebe29b07f5 Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sat, 21 Oct 2017 20:22:05 -0400 Subject: [PATCH 1/8] whitespace and jquery --- web/skins/classic/views/event.php | 9 +++++---- web/skins/classic/views/js/event.js | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 5990b2e45..ad82562cf 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -36,12 +36,13 @@ if ( $user['MonitorIds'] ) { } $Monitor = $Event->Monitor(); -if ( isset( $_REQUEST['rate'] ) ) +if (isset($_REQUEST['rate'])) { $rate = validInt($_REQUEST['rate']); -else - $rate = reScale( RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE ); +} else { + $rate = reScale(RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE); +} -if ( isset( $_REQUEST['scale'] ) ) { +if (isset($_REQUEST['scale'])) { $scale = validInt($_REQUEST['scale']); } else if ( isset( $_COOKIE['zmEventScale'.$Event->MonitorId()] ) ) { $scale = $_COOKIE['zmEventScale'.$Event->MonitorId()]; diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 8b88a24fc..df02663f1 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -924,11 +924,11 @@ function setupListener() { function initPage() { //FIXME prevent blocking...not sure what is happening or best way to unblock - if ( $('videoobj') ) { + if ($j('#videoobj').length) { vid = videojs("videoobj"); initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues after videojs is. should be only call to initialAlarmCues on vjs streams } - if ( vid ) { + if (vid) { /* setupListener(); vid.removeAttribute("controls"); From f2f2aa8720ef17ffa23f6b449079d089ac8cef1f Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sat, 21 Oct 2017 21:55:37 -0400 Subject: [PATCH 2/8] Replay improvement and overlays --- web/skins/classic/css/classic/views/event.css | 13 ++++++++++--- web/skins/classic/css/dark/views/event.css | 15 +++++++++++---- web/skins/classic/css/flat/views/event.css | 13 ++++++++++--- web/skins/classic/views/js/event.js | 16 +++++++++++----- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/web/skins/classic/css/classic/views/event.css b/web/skins/classic/css/classic/views/event.css index eeae363c4..1a9ed51fa 100644 --- a/web/skins/classic/css/classic/views/event.css +++ b/web/skins/classic/css/classic/views/event.css @@ -1,6 +1,10 @@ -.vjsMessage { - font-size: 2em; - line-height: 1.5; +#content .vjsMessage { + width: 100%; + position: absolute; + left: 0; + z-index: 10; + margin: 0; + font-size: 200%; color: white; background-color: black; display: inline-block; @@ -40,6 +44,7 @@ span.noneCue { #eventVideo { display: inline-block; + postion: relative; } #menuBar1 { @@ -112,6 +117,8 @@ span.noneCue { } #imageFeed { + display: inline-block; + position: relative; text-align: center; } diff --git a/web/skins/classic/css/dark/views/event.css b/web/skins/classic/css/dark/views/event.css index 715cc0c07..9e98507d1 100644 --- a/web/skins/classic/css/dark/views/event.css +++ b/web/skins/classic/css/dark/views/event.css @@ -1,6 +1,10 @@ -.vjsMessage { - font-size: 2em; - line-height: 1.5; +#content .vjsMessage { + width: 100%; + position: absolute; + left: 0; + z-index: 10; + margin: 0; + font-size: 200%; color: white; background-color: black; display: inline-block; @@ -95,6 +99,8 @@ span.noneCue { } #imageFeed { + display: inline-block; + position: relative; text-align: center; } @@ -255,7 +261,8 @@ span.noneCue { } #eventVideo { -display: inline-block; + display: inline-block; + position: relative; } #thumbsKnob { diff --git a/web/skins/classic/css/flat/views/event.css b/web/skins/classic/css/flat/views/event.css index 963e644ef..38f57edc5 100644 --- a/web/skins/classic/css/flat/views/event.css +++ b/web/skins/classic/css/flat/views/event.css @@ -1,6 +1,10 @@ -.vjsMessage { - font-size: 2em; - line-height: 1.5; +#content .vjsMessage { + width: 100%; + position: absolute; + left: 0; + z-index: 10; + margin: 0; + font-size: 200%; color: white; background-color: black; display: inline-block; @@ -100,6 +104,8 @@ span.noneCue { visibility: hidden; } #imageFeed { + display: inline-block; + position: relative; text-align: center; } @@ -272,6 +278,7 @@ span.noneCue { } #eventVideo { display: inline-block; + position: relative; } #video-controls { diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index df02663f1..375452db7 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -1,9 +1,10 @@ var vid = null; -function vjsReplay(endTime) { - var video = videojs('videoobj').ready(function(){ +function vjsReplay() { + vid.ready(function(){ var player = this; player.on('ended', function() { + var endTime = (Date.parse(eventData.EndTime)).getTime(); switch(replayMode.value) { case 'none': break; @@ -12,19 +13,23 @@ function vjsReplay(endTime) { break; case 'all': if (nextEventId == 0) { - $j("#videoobj").html('
No more events
'); + let overLaid = $j("#videoobj"); + overLaid.append('No more events
'); } else { var nextStartTime = nextEventStartTime.getTime(); //nextEventStartTime.getTime() is a mootools workaround, highjacks Date.parse if (nextStartTime <= endTime) { streamNext( true ); return; } - $j("#videoobj").html(''); + let overLaid = $j("#videoobj"); + vid.pause(); + overLaid.append(''); var gapDuration = (new Date().getTime()) + (nextStartTime - endTime); + let messageP = $j(".vjsMessage"); var x = setInterval(function() { var now = new Date().getTime(); var remainder = new Date(Math.round(gapDuration - now)).toISOString().substr(11,8); - $j(".vjsMessage").html(remainder + ' to next event.'); + messageP.html(remainder + ' to next event.'); if (remainder < 0) { clearInterval(x); streamNext( true ); @@ -927,6 +932,7 @@ function initPage() { if ($j('#videoobj').length) { vid = videojs("videoobj"); initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues after videojs is. should be only call to initialAlarmCues on vjs streams + vjsReplay(); } if (vid) { /* From 1eb2edd95c18efeb8702f32c33e4f453399cb69b Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sat, 21 Oct 2017 21:57:24 -0400 Subject: [PATCH 3/8] Converge initial eventData with ajax The initial eventData object on page load didn't have most of the information that the ajax call gave it. --- web/ajax/status.php | 1 + web/skins/classic/views/js/event.js.php | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index ed185d918..82929c20b 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -108,6 +108,7 @@ $statusData = array( "elements" => array( "Id" => array( "sql" => "Events.Id" ), "MonitorId" => true, + "MonitorName" => array("sql" => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"), "Name" => true, "Cause" => true, "StartTime" => true, diff --git a/web/skins/classic/views/js/event.js.php b/web/skins/classic/views/js/event.js.php index b8dbd8d94..5a3e083de 100644 --- a/web/skins/classic/views/js/event.js.php +++ b/web/skins/classic/views/js/event.js.php @@ -30,13 +30,18 @@ var eventData = { MonitorId: 'MonitorId() ?>', Width: 'Width() ?>', Height: 'Height() ?>', - Length: 'Length() ?>' + Length: 'Length() ?>', + StartTime: 'StartTime() ?>', + EndTime: 'EndTime() ?>', + MonitorName: 'Name() ?>' }; var filterQuery = ''; var sortQuery = ''; -var scale = ; +var scale = ""; +var LabelFormat = "LabelFormat())?>"; + var canEditEvents = ; var streamTimeout = ; From ff8d06763992204bd5a942c0b80043294e91a9a3 Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sat, 21 Oct 2017 22:02:46 -0400 Subject: [PATCH 4/8] alarmCues improvements Consolidate selectors and improve edge cases where skew could cause overflow --- web/skins/classic/js/video-js-skin.css | 2 +- web/skins/classic/views/event.php | 2 +- web/skins/classic/views/js/event.js | 13 ++++--------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/web/skins/classic/js/video-js-skin.css b/web/skins/classic/js/video-js-skin.css index 447c22c44..d2a5cc529 100644 --- a/web/skins/classic/js/video-js-skin.css +++ b/web/skins/classic/js/video-js-skin.css @@ -14,7 +14,7 @@ font-size: .3em; } -.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar.vjs-zm { +.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { visibility: visible; opacity: 1; bottom: -2em; diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index ad82562cf..313887398 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -192,7 +192,7 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { } } // end if stream method ?> - +diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index c6375fcb2..8a1dfd2bc 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -177,7 +177,7 @@ var zmsBroke = false; //Use alternate navigation if zms has crashed function getCmdResponse( respObj, respText ) { if ( checkStreamForErrors( "getCmdResponse", respObj ) ) { console.log('Got an error from getCmdResponse'); - var zmsBroke = true; + zmsBroke = true; return; } @@ -302,7 +302,11 @@ function streamFastRev( action ) { function streamPrev(action) { if (action) { - if (vid || PrevEventDefVideoPath.indexOf("view_video") >=0 || $j("#vjsMessage").length || zmsBroke) { //handles this or prev being video.js, or end of events + $j(".vjsMessage").remove(); + if (vid && PrevEventDefVideoPath.indexOf("view_video") > 0) { + CurEventDefVideoPath = PrevEventDefVideoPath; + eventQuery(prevEventId); + } else if (zmsBroke || (vid && PrevEventDefVideoPath.indexOf("view_video") < 0) || $j("#vjsMessage").length || PrevEventDefVideoPath.indexOf("view_video") > 0) {//zms broke, leaving videojs, last event, moving to videojs location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery); } else { streamReq.send(streamParms+"&command="+CMD_PREV); @@ -312,13 +316,22 @@ function streamPrev(action) { function streamNext(action) { if (action) { + $j(".vjsMessage").remove();//This shouldn't happen if (nextEventId == 0) { //handles deleting last event. - let replaceStream = $j(vid ? "#videoobj" : "#evtStream"); - replaceStream.replaceWith('
No more events
'); - } else if (vid || NextEventDefVideoPath.indexOf("view_video") >=0 || zmsBroke) { //handles current or next switch to video.js + vid ? vid.pause() : streamPause(); + let hideContainer = $j( vid ? "#eventVideo" : "#imageFeed"); + let hideStream = $j(vid ? "#videoobj" : "#evtStream").height() + (vid ? 0 :$j("#progressBar").height()); + hideContainer.prepend('No more events
'); + if (vid == null) zmsBroke = true; + return; + } + if (vid && NextEventDefVideoPath.indexOf("view_video") > 0) { //on and staying with videojs + CurEventDefVideoPath = NextEventDefVideoPath; + eventQuery(nextEventId); + } else if (zmsBroke || (vid && NextEventDefVideoPath.indexOf("view_video") < 0) || NextEventDefVideoPath.indexOf("view_video") > 0) {//reload zms, leaving vjs, moving to vjs location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery); } else { - streamReq.send( streamParms+"&command="+CMD_NEXT ); + streamReq.send(streamParms+"&command="+CMD_NEXT); } } } @@ -349,6 +362,7 @@ function streamQuery() { var slider = null; var scroll = null; +var CurEventDefVideoPath = null; function getEventResponse( respObj, respText ) { if ( checkStreamForErrors( "getEventResponse", respObj ) ) { @@ -376,6 +390,7 @@ function getEventResponse( respObj, respText ) { $('dataScore').set( 'text', eventData.TotScore+"/"+eventData.AvgScore+"/"+eventData.MaxScore ); $('eventName').setProperty( 'value', eventData.Name ); + history.replaceState(null, null, '?view=event&eid=' + eventData.Id + filterQuery + sortQuery);//if popup removed, check if this allows forward if ( canEditEvents ) { if ( parseInt(eventData.Archived) ) { $('archiveEvent').addClass( 'hidden' ); @@ -388,7 +403,13 @@ function getEventResponse( respObj, respText ) { // Technically, events can be different sizes, so may need to update the size of the image, but it might be better to have it stay scaled... //var eventImg = $('eventImage'); //eventImg.setStyles( { 'width': eventData.width, 'height': eventData.height } ); - drawProgressBar(); + if (vid) { + vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use + initialAlarmCues(eventData.Id);//ajax and render, new event + addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime); + } else { + drawProgressBar(); + } nearEventsQuery( eventData.Id ); } @@ -794,7 +815,7 @@ function videoEvent() { // Called on each event load because each event can be a different width function drawProgressBar() { - var barWidth = (eventData.Width * $j('#scale').val()) / SCALE_BASE; + let barWidth = $j('#evtStream').width(); $j('#progressBar').css( 'width', barWidth ); } @@ -808,7 +829,7 @@ function updateProgressBar() { } // end function updateProgressBar() // Handles seeking when clicking on the progress bar. -function progressBarSeek (){ +function progressBarNav (){ $j('#progressBar').click(function(e){ var x = e.pageX - $j(this).offset().left; var seekTime = (x / $j('#progressBar').width()) * parseFloat(eventData.Length); @@ -927,7 +948,10 @@ function initPage() { //FIXME prevent blocking...not sure what is happening or best way to unblock if ($j('#videoobj').length) { vid = videojs("videoobj"); - initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues after videojs is. should be only call to initialAlarmCues on vjs streams + addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime); + $j(".vjs-progress-control").append('');//add a place for videojs only on first load + nearEventsQuery(eventData.Id); + initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues after videojs is initialized vjsReplay(); } if (vid) { @@ -949,9 +973,10 @@ function initPage() { window.videoobj.load(); streamPlay(); */ } else { - progressBarSeek (); + progressBarNav (); streamCmdTimer = streamQuery.delay( 250 ); eventQuery.pass( eventData.Id ).delay( 500 ); + initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues for zms. if ( canStreamNative ) { var streamImg = $('imageFeed').getElement('img'); From 3fe46cbaff7f82e16ba024c676b2be1166033aed Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sat, 21 Oct 2017 22:11:29 -0400 Subject: [PATCH 6/8] Scale to Fit Added a scale to fit option. When navigating between events of different size they will fill the window. Turned on when any event uses it, turned off when any event turns it off. --- web/skins/classic/includes/config.php | 3 ++ web/skins/classic/views/event.php | 4 +- web/skins/classic/views/js/event.js | 65 +++++++++++++++++++-------- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/web/skins/classic/includes/config.php b/web/skins/classic/includes/config.php index c97b9ba64..763a2b8cc 100644 --- a/web/skins/classic/includes/config.php +++ b/web/skins/classic/includes/config.php @@ -31,6 +31,7 @@ $rates = array( ); $scales = array( + 'auto' => translate('Scale to Fit'), '' => translate('Fixed Width/Height'), '400' => '4x', '300' => '3x', @@ -44,6 +45,8 @@ $scales = array( '12.5' => '1/8x', ); +if (isset($_REQUEST['view'])) unset($scales[$_REQUEST['view'] == 'event' ? '' : 'auto']); //Remove the option we aren't using on montage or event + $bandwidth_options = array( 'high' => translate('High'), 'medium' => translate('Medium'), diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 9bd732292..263009ffe 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -44,7 +44,9 @@ if (isset($_REQUEST['rate'])) { if (isset($_REQUEST['scale'])) { $scale = validInt($_REQUEST['scale']); -} else if ( isset( $_COOKIE['zmEventScale'.$Event->MonitorId()] ) ) { +} else if (isset($_COOKIE['zmEventScaleAuto'])) { //If we're using scale to fit use it on all monitors + $scale = 'auto'; +} else if (isset($_COOKIE['zmEventScale'.$Event->MonitorId()])) { $scale = $_COOKIE['zmEventScale'.$Event->MonitorId()]; } else { $scale = reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ); diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 8a1dfd2bc..d7d46151d 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -135,27 +135,54 @@ function setButtonState( element, butClass ) { } } +var resizeTimer; + +function endOfResize(e) { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(changeScale, 250); +} + +function scaleToFit () { + $j(window).on('resize', endOfResize) //set delayed scaling when Scale to Fit is selected + let ratio = eventData.Width/eventData.Height; + let container = $j('#content'); + let feed = $j(vid ? '#videoobj' : '#evtStream'); + let viewPort = $j(window); + let newHeight = viewPort.height() - (container.outerHeight(true) - feed.outerHeight(true)); + let newWidth = ratio * newHeight; + if (newWidth > container.innerWidth()) { + newWidth = container.innerWidth(); + newHeight = newWidth / ratio; + } + return {width: Math.floor(newWidth), height: Math.floor(newHeight)}; +} + function changeScale() { - var scale = $('scale').get('value'); - var baseWidth = eventData.Width; - var baseHeight = eventData.Height; - var newWidth = ( baseWidth * scale ) / SCALE_BASE; - var newHeight = ( baseHeight * scale ) / SCALE_BASE; - if ( vid ) { - // Using video.js - $j("#videoobj").width(newWidth); - $j("#videoobj").height(newHeight); - $j("div.alarmCue").html(renderAlarmCues());//just re-render alarmCues. skip ajax call - Cookie.write( 'zmEventScale'+eventData.MonitorId, scale, { duration: 10*365 } ); + let scale = $j('#scale').val(); + if (scale == "auto") { + let newSize = scaleToFit(); + var newWidth = newSize.width; + var newHeight = newSize.height; } else { - streamScale( scale ); - var streamImg = document.getElementById('evtStream'); - streamImg.style.width = newWidth + "px"; - streamImg.style.height = newHeight + "px"; - $j("#alarmCueJpeg").width(newWidth); + $j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active + var newWidth = eventData.Width * scale / SCALE_BASE; + var newHeight = eventData.Height * scale / SCALE_BASE; + } + let alarmCue = $j('div.alarmCue'); + let eventViewer = $j(vid ? '#videoobj' : '#evtStream') + eventViewer.width(newWidth); + eventViewer.height(newHeight); + if ( !vid ) { // zms needs extra sizing + streamScale(scale == "auto" ? Math.round(newWidth / eventData.Width * SCALE_BASE) : scale); + alarmCue.width(newWidth); drawProgressBar(); - $j("#alarmCueJpeg").html(renderAlarmCues()); - Cookie.write( 'zmEventScale'+eventData.MonitorId, scale, { duration: 10*365 } ); + } + alarmCue.html(renderAlarmCues());//just re-render alarmCues. skip ajax call + if (scale == "auto") { + Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365}); + }else{ + Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365}); + Cookie.dispose('zmEventScaleAuto'); } } @@ -389,7 +416,6 @@ function getEventResponse( respObj, respText ) { $('dataFrames').set( 'text', eventData.Frames+"/"+eventData.AlarmFrames ); $('dataScore').set( 'text', eventData.TotScore+"/"+eventData.AvgScore+"/"+eventData.MaxScore ); $('eventName').setProperty( 'value', eventData.Name ); - history.replaceState(null, null, '?view=event&eid=' + eventData.Id + filterQuery + sortQuery);//if popup removed, check if this allows forward if ( canEditEvents ) { if ( parseInt(eventData.Archived) ) { @@ -985,6 +1011,7 @@ function initPage() { $(streamImg).addEvent( 'click', function( event ) { handleClick( event ); } ); } } +if (scale == "auto") changeScale(); } // Kick everything off From 298085ae93b7f137b4b79d98d546a2a86edcfc62 Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sun, 22 Oct 2017 15:02:36 -0400 Subject: [PATCH 7/8] Fix archive nulling vid src --- web/skins/classic/views/js/event.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index d7d46151d..021f19164 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -429,10 +429,11 @@ function getEventResponse( respObj, respText ) { // Technically, events can be different sizes, so may need to update the size of the image, but it might be better to have it stay scaled... //var eventImg = $('eventImage'); //eventImg.setStyles( { 'width': eventData.width, 'height': eventData.height } ); - if (vid) { + if (vid && CurEventDefVideoPath) { vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use initialAlarmCues(eventData.Id);//ajax and render, new event addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime); + CurEventDefVideoPath = null; } else { drawProgressBar(); } From 1bddec154845486b4dae528c11c0588179906053 Mon Sep 17 00:00:00 2001 From: digital-gnome <31593470+digital-gnome@users.noreply.github.com> Date: Sun, 22 Oct 2017 17:23:04 -0400 Subject: [PATCH 8/8] Bypass refreshParentWindow This hasn't worked for a while. It looks like it's the result of a fix for filter window redirecting. It's possible other things use it but this fixes event deletion without touching anything else. --- web/skins/classic/views/js/event.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 021f19164..102d4a956 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -742,6 +742,7 @@ function getActResponse( respObj, respText ) { return; if ( respObj.refreshParent ) + if (refreshParent == false) refreshParent = true; //Bypass filter window redirect fix. refreshParentWindow(); if ( respObj.refreshEvent )