diff --git a/.eslintignore b/.eslintignore index f5529e8ee..55fe41a49 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,6 +5,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js web/skins/classic/js/bootstrap-4.5.0.js +web/skins/classic/js/bootstrap.bundle.min.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js diff --git a/web/ajax/status.php b/web/ajax/status.php index 7ddc85176..0d17213a5 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -387,6 +387,7 @@ function getFrameImage() { $sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?'; if ( !($frame = dbFetchOne($sql, NULL, array($eventId, $frameId))) ) { + ZM\Error("Frame not found for event $eventId frame $frameId"); $frame = array(); $frame['EventId'] = $eventId; $frame['FrameId'] = $frameId; diff --git a/web/skins/classic/css/base/views/timeline.css b/web/skins/classic/css/base/views/timeline.css index 0068767b5..5c09fb4f7 100644 --- a/web/skins/classic/css/base/views/timeline.css +++ b/web/skins/classic/css/base/views/timeline.css @@ -36,9 +36,17 @@ #topPanel { position: relative; - height: 220px; + min-height: 220px; margin: 4px auto 6px; } +#topPanel:after { + content: "."; + display: block; + height: 0; + font-size: 0; + clear: both; + visibility: hidden; +} #topPanel .imagePanel { text-align: right; @@ -87,6 +95,7 @@ } #topPanel #navPanel { + float: left; width: 100%; height: 70px; margin: 4px auto; diff --git a/web/skins/classic/css/base/views/timeline.css.php b/web/skins/classic/css/base/views/timeline.css.php index d993ce9a0..586fdbe85 100644 --- a/web/skins/classic/css/base/views/timeline.css.php +++ b/web/skins/classic/css/base/views/timeline.css.php @@ -8,7 +8,9 @@ .chartSize { - height: px; +/* + min-height: px; +*/ } .graphSize { diff --git a/web/skins/classic/js/bootstrap.bundle.min.js b/web/skins/classic/js/bootstrap.bundle.min.js index 02634181e..a33c857ad 120000 --- a/web/skins/classic/js/bootstrap.bundle.min.js +++ b/web/skins/classic/js/bootstrap.bundle.min.js @@ -1 +1 @@ -bootstrap.min.js \ No newline at end of file +bootstrap-4.5.0.min.js \ No newline at end of file diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index 97e735b34..0a18353e7 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -1,4 +1,3 @@ -var events = {}; function showEvent(e) { var eid = e.getAttribute('data-event-id'); @@ -33,34 +32,31 @@ function showEventDetail(eventHtml) { function eventDataResponse(respObj, respText) { var zm_event = respObj.event; - if ( !zm_event ) { + if (!zm_event) { console.log('Null event'); return; } events[zm_event.Id] = zm_event; - if ( respObj.loopback ) { + if (respObj.loopback) { requestFrameData(zm_event.Id, respObj.loopback); } } -function frameDataResponse( respObj, respText ) { +function frameDataResponse(respObj, respText) { var frame = respObj.frameimage; - if ( !frame.FrameId ) { + if (!frame.FrameId) { console.log('Null frame'); return; } var zm_event = events[frame.EventId]; - if ( !zm_event ) { + if (!zm_event) { console.error('No event '+frame.eventId+' found'); return; } - if ( !zm_event['frames'] ) { - console.log('No frames data in event response'); - console.log(zm_event); - console.log(respObj); + if (!zm_event['frames']) { zm_event['frames'] = {}; } @@ -71,15 +67,14 @@ function frameDataResponse( respObj, respText ) { } function showEventData(zm_event, frameId) { - if ( zm_event ) { - if ( zm_event['frames'] ) { - if ( zm_event['frames'][frameId] ) { - $('instruction').addClass('hidden'); - eventData = $('eventData'+zm_event.MonitorId); - eventData.empty(); - eventData.adopt(zm_event['frames'][frameId]['html']); - eventData.removeClass('hidden'); - var imagePath = 'index.php?view=image&eid='+eventId+'&fid='+frameId; + if (zm_event) { + if (zm_event['frames']) { + if (zm_event['frames'][frameId]) { + $j('#instruction').hide(); + eventData = $j('#eventData'+zm_event.MonitorId); + eventData.html(zm_event['frames'][frameId]['html']); + eventData.show(); + var imagePath = 'index.php?view=image&eid='+zm_event.Id+'&fid='+frameId; loadEventImage(imagePath, zm_event, frameId); return; } else { @@ -87,6 +82,7 @@ function showEventData(zm_event, frameId) { } } else { console.log('No frames'); + requestFrameData(zm_event.Id, frameId); } } else { console.log('No event'); @@ -105,10 +101,10 @@ function frameQuery(data) { .fail(logAjaxFail); } -function requestFrameData( eventId, frameId ) { +function requestFrameData(eventId, frameId) { var data = {}; - if ( !events[eventId] ) { + if (!events[eventId]) { data.id = eventId; data.loopback = frameId; eventQuery(data); @@ -121,26 +117,36 @@ function requestFrameData( eventId, frameId ) { function previewEvent(slot) { eventId = slot.getAttribute('data-event-id'); frameId = slot.getAttribute('data-frame-id'); - if ( events[eventId] && events[eventId]['frames'] && events[eventId]['frames'][frameId] ) { - showEventData(eventId, frameId); + if (events[eventId] && events[eventId]['frames'] && events[eventId]['frames'][frameId]) { + showEventData(events[eventId], frameId); } else { requestFrameData(eventId, frameId); } } -function loadEventImage( imagePath, zm_event, fid ) { - var imageSrc = $('imageSrc'+zm_event.MonitorId); +function loadEventImage(imagePath, zm_event, fid) { + if (!zm_event) { + console.log("No event object passed to loadEventImage"); + return; + } + + const imageSrc = $j('#imageSrc'+zm_event.MonitorId); imageSrc.show(); - imageSrc.setProperty('src', imagePath); - imageSrc.setAttribute('data-event-id', zm_event.Id); - imageSrc.setAttribute('data-frame-id', fid); - imageSrc.onclick=window['showEvent'].bind(imageSrc, imageSrc); + imageSrc.attr('src', imagePath); + imageSrc.attr('data-event-id', zm_event.Id); + imageSrc.attr('data-frame-id', fid); + imageSrc.off('click'); + imageSrc.on('click', function() { + showEvent(this); + }); - var eventData = $('eventData'.zm_event.MonitorId); - if ( eventData ) { - eventData.removeEvent('click'); - eventData.addEvent('click', showEvent.pass()); + var eventData = $j('#eventData'+zm_event.MonitorId); + if ( eventData.length ) { + eventData.off('click'); + eventData.on('click', function() { + showEvent(this); + }); } else { console.log("No eventdata area found for monitor " + zm_event.MonitorId); } @@ -204,6 +210,11 @@ function initPage() { window.location.assign('?view=events'+filterQuery); }); + for (const mid in monitors) { + const monitor = monitors[mid]; + showEventData(events[monitor.FirstEventId], 1); + } + // Bind the data-on-click attributes associated with a div divDataOnClick(); } diff --git a/web/skins/classic/views/js/timeline.js.php b/web/skins/classic/views/js/timeline.js.php index 474e403e0..aa9d73986 100644 --- a/web/skins/classic/views/js/timeline.js.php +++ b/web/skins/classic/views/js/timeline.js.php @@ -6,18 +6,28 @@ global $maxTime; global $range; global $majXScale; + global $monEventSlots; + global $monFrameSlots; ?> var filterQuery = ''; +var events = {}; $field(); } + $firstEvent = reset($monEventSlots[$monitor->Id()])['event']; + + $jsMonitor['FirstEventId'] = $firstEvent['Id']; + echo 'events['.$firstEvent['Id'].']='.json_encode($firstEvent).';'.PHP_EOL; + $jsMonitors[$monitor->Id()] = $jsMonitor; } ?> @@ -30,3 +40,4 @@ var midTime = ''; var maxTime = ''; var range = ''; var zoomout_range = ''; + diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index 42417503b..c938714a2 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -17,12 +17,12 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canView('Events') ) { +if (!canView('Events')) { $view = 'error'; return; } -foreach ( getSkinIncludes('includes/timeline_functions.php') as $includeFile ) +foreach (getSkinIncludes('includes/timeline_functions.php') as $includeFile) require_once $includeFile; // @@ -313,7 +313,7 @@ if ( !$events_result ) { $max_aspect_ratio = 0; -while( $event = $events_result->fetch(PDO::FETCH_ASSOC) ) { +while ($event = $events_result->fetch(PDO::FETCH_ASSOC)) { if ( !isset($monitors[$event['MonitorId']]) ) { $monitor = $monitors[$event['MonitorId']] = ZM\Monitor::find_one(array('Id'=>$event['MonitorId'])); $monEventSlots[$event['MonitorId']] = array(); @@ -361,7 +361,7 @@ while( $event = $events_result->fetch(PDO::FETCH_ASSOC) ) { $i = $startIndex; if ( !isset($currFrameSlots[$i]) ) { - $currFrameSlots[$i] = array('count'=>1, 'value'=>$event['MaxScore'], 'event'=>$event, 'frame'=>$frame); + $currFrameSlots[$i] = array('count'=>1, 'value'=>$event['MaxScore'], 'event'=>$event, 'frame'=>$frame, 'id'=>$frame['FrameId']); } else { $currFrameSlots[$i]['count']++; if ( $event['MaxScore'] > $currFrameSlots[$i]['value'] ) { @@ -434,10 +434,10 @@ $majYScale = getYScale( $chart['grid']['y']['major']['max']); // Optimise boxes -foreach( array_keys($monEventSlots) as $monitorId ) { - unset( $currEventSlots ); +foreach (array_keys($monEventSlots) as $monitorId) { + unset($currEventSlots); $currEventSlots = &$monEventSlots[$monitorId]; - for ( $i = 0; $i < $chart['graph']['width']; $i++ ) { + for ($i = 0; $i < $chart['graph']['width']; $i++) { if ( isset($currEventSlots[$i]) ) { if ( isset($currSlot) ) { if ( $currSlot['event']['Id'] == $currEventSlots[$i]['event']['Id'] ) { @@ -692,13 +692,13 @@ xhtmlHeaders(__FILE__, translate('Timeline')); -
-
+
+
>
<?php echo translate('ViewEvent') ?>
-
+
>