Rough in the ui for Snapshots
This commit is contained in:
parent
c9170a87b2
commit
11c2318a05
|
@ -0,0 +1,56 @@
|
||||||
|
--
|
||||||
|
-- Add HomeView to Users
|
||||||
|
--
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Users'
|
||||||
|
AND column_name = 'HomeView'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column HomeView already exists in Users'",
|
||||||
|
"ALTER TABLE `Users` ADD `HomeView` varchar(64) NOT NULL DEFAULT '' AFTER `APIEnabled`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE table_name = 'Snapshots'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Snapshots table exists'",
|
||||||
|
"CREATE TABLE Snapshots (
|
||||||
|
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||||
|
`Name` VARCHAR(64),
|
||||||
|
`Description` TEXT,
|
||||||
|
`CreatedBy` int(10),
|
||||||
|
`CreatedOn` datetime default NULL,
|
||||||
|
PRIMARY KEY(Id)
|
||||||
|
) ENGINE=InnoDB;"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE table_name = 'Snapshot_Events'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Snapshot_Events table exists'",
|
||||||
|
"CREATE TABLE Snapshot_Events (
|
||||||
|
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||||
|
`SnapshotId` int(10) unsigned NOT NULL,
|
||||||
|
FOREIGN KEY (`SnapshotId`) REFERENCES `Snapshots` (`Id`) ON DELETE CASCADE,
|
||||||
|
`EventId` bigint unsigned NOT NULL,
|
||||||
|
FOREIGN KEY (`EventId`) REFERENCES `Events` (`Id`) ON DELETE CASCADE,
|
||||||
|
KEY `Snapshot_Events_SnapshotId_idx` (`SnapshotId`),
|
||||||
|
PRIMARY KEY(Id)
|
||||||
|
) ENGINE=InnoDB;"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -0,0 +1,227 @@
|
||||||
|
<?php
|
||||||
|
require_once('includes/Snapshot.php');
|
||||||
|
require_once('includes/Filter.php');
|
||||||
|
$message = '';
|
||||||
|
$data = array();
|
||||||
|
|
||||||
|
//
|
||||||
|
// INITIALIZE AND CHECK SANITY
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( !canView('Events') ) $message = 'Insufficient permissions for user '.$user['Username'];
|
||||||
|
|
||||||
|
if ( empty($_REQUEST['task']) ) {
|
||||||
|
$message = 'Must specify a task';
|
||||||
|
} else {
|
||||||
|
$task = $_REQUEST['task'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty($_REQUEST['ids']) ) {
|
||||||
|
if ( isset($_REQUEST['task']) && $_REQUEST['task'] != 'query' ) $message = 'No snapshot id(s) supplied';
|
||||||
|
} else {
|
||||||
|
$eids = $_REQUEST['ids'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $message ) {
|
||||||
|
ajaxError($message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search contains a user entered string to search on
|
||||||
|
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
|
||||||
|
|
||||||
|
// Advanced search contains an array of "column name" => "search text" pairs
|
||||||
|
// Bootstrap table sends json_ecoded array, which we must decode
|
||||||
|
$advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], JSON_OBJECT_AS_ARRAY) : array();
|
||||||
|
|
||||||
|
// Sort specifies the name of the column to sort on
|
||||||
|
$sort = 'Id';
|
||||||
|
if ( isset($_REQUEST['sort']) ) {
|
||||||
|
$sort = $_REQUEST['sort'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset specifies the starting row to return, used for pagination
|
||||||
|
$offset = 0;
|
||||||
|
if ( isset($_REQUEST['offset']) ) {
|
||||||
|
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) {
|
||||||
|
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
|
||||||
|
} else {
|
||||||
|
$offset = $_REQUEST['offset'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order specifies the sort direction, either asc or desc
|
||||||
|
$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC';
|
||||||
|
|
||||||
|
// Limit specifies the number of rows to return
|
||||||
|
// Set the default to 0 for events view, to prevent an issue with ALL pagination
|
||||||
|
$limit = 0;
|
||||||
|
if ( isset($_REQUEST['limit']) ) {
|
||||||
|
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
||||||
|
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
||||||
|
} else {
|
||||||
|
$limit = $_REQUEST['limit'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// MAIN LOOP
|
||||||
|
//
|
||||||
|
|
||||||
|
switch ( $task ) {
|
||||||
|
case 'delete' :
|
||||||
|
if ( !canEdit('Events') ) {
|
||||||
|
ajaxError('Insufficient permissions for user '.$user['Username']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $ids as $id ) $data[] = deleteRequest($id);
|
||||||
|
break;
|
||||||
|
case 'query' :
|
||||||
|
$data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
ZM\Fatal("Unrecognised task '$task'");
|
||||||
|
} // end switch task
|
||||||
|
|
||||||
|
ajaxResponse($data);
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION DEFINITIONS
|
||||||
|
//
|
||||||
|
|
||||||
|
function deleteRequest($id) {
|
||||||
|
$message = array();
|
||||||
|
$snapshot = new ZM\Snapshot($id);
|
||||||
|
if ( !$snapshot->Id() ) {
|
||||||
|
$message[] = array($id=>'Snapshot not found.');
|
||||||
|
//} else if ( $snapshot->Archived() ) {
|
||||||
|
//$message[] = array($id=>'Event is archived, cannot delete it.');
|
||||||
|
} else {
|
||||||
|
$snapshot->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) {
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
'total' => 0,
|
||||||
|
'totalNotFiltered' => 0,
|
||||||
|
'rows' => array(),
|
||||||
|
'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Put server pagination code here
|
||||||
|
// The table we want our data from
|
||||||
|
$table = 'Snapshots';
|
||||||
|
|
||||||
|
// The names of the dB columns in the events table we are interested in
|
||||||
|
$columns = array('Id', 'Name', 'Description', 'CreatedDateTime');
|
||||||
|
|
||||||
|
if ( !in_array($sort, array_merge($columns)) ) {
|
||||||
|
ZM\Error('Invalid sort field: ' . $sort);
|
||||||
|
$sort = 'Id';
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = array();
|
||||||
|
$likes = array();
|
||||||
|
$where = '';
|
||||||
|
|
||||||
|
$col_str = '*';
|
||||||
|
$sql = 'SELECT ' .$col_str. ' FROM `Snapshots`'.$where.' ORDER BY '.$sort.' '.$order;
|
||||||
|
|
||||||
|
$unfiltered_rows = array();
|
||||||
|
$event_ids = array();
|
||||||
|
|
||||||
|
ZM\Debug('Calling the following sql query: ' .$sql);
|
||||||
|
$query = dbQuery($sql, $values);
|
||||||
|
if ( $query ) {
|
||||||
|
while ( $row = dbFetchNext($query) ) {
|
||||||
|
$snapshot = new ZM\Snapshot($row);
|
||||||
|
$snapshot->remove_from_cache();
|
||||||
|
$snapshot_ids[] = $snapshot->Id();
|
||||||
|
$unfiltered_rows[] = $row;
|
||||||
|
} # end foreach row
|
||||||
|
}
|
||||||
|
|
||||||
|
ZM\Debug('Have ' . count($unfiltered_rows) . ' snapshots matching base filter.');
|
||||||
|
|
||||||
|
$filtered_rows = null;
|
||||||
|
|
||||||
|
if ( count($advsearch) or $search != '' ) {
|
||||||
|
$search_filter = new ZM\Filter();
|
||||||
|
|
||||||
|
$search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$event_ids));
|
||||||
|
|
||||||
|
// There are two search bars in the log view, normal and advanced
|
||||||
|
// Making an exuctive decision to ignore the normal search, when advanced search is in use
|
||||||
|
// Alternatively we could try to do both
|
||||||
|
if ( count($advsearch) ) {
|
||||||
|
$terms = array();
|
||||||
|
foreach ( $advsearch as $col=>$text ) {
|
||||||
|
$terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text);
|
||||||
|
} # end foreach col in advsearch
|
||||||
|
$terms[0]['obr'] = 1;
|
||||||
|
$terms[count($terms)-1]['cbr'] = 1;
|
||||||
|
$search_filter->addTerms($terms);
|
||||||
|
} else if ( $search != '' ) {
|
||||||
|
$search = '%' .$search. '%';
|
||||||
|
$terms = array();
|
||||||
|
foreach ( $columns as $col ) {
|
||||||
|
$terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search);
|
||||||
|
}
|
||||||
|
$terms[0]['obr'] = 1;
|
||||||
|
$terms[0]['cnj'] = 'and';
|
||||||
|
$terms[count($terms)-1]['cbr'] = 1;
|
||||||
|
$search_filter = $search_filter->addTerms($terms, array('obr'=>1, 'cbr'=>1, 'op'=>'OR'));
|
||||||
|
} # end if search
|
||||||
|
|
||||||
|
$sql = 'SELECT ' .$col_str. ' FROM `Snapshots` WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order;
|
||||||
|
ZM\Debug('Calling the following sql query: ' .$sql);
|
||||||
|
$filtered_rows = dbFetchAll($sql);
|
||||||
|
ZM\Debug('Have ' . count($filtered_rows) . ' snapshots matching search filter.');
|
||||||
|
} else {
|
||||||
|
$filtered_rows = $unfiltered_rows;
|
||||||
|
} # end if search_filter->terms() > 1
|
||||||
|
|
||||||
|
$returned_rows = array();
|
||||||
|
foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) {
|
||||||
|
$snapshot = new ZM\Snapshot($row);
|
||||||
|
|
||||||
|
//$scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width());
|
||||||
|
//$imgSrc = $event->getThumbnailSrc(array(), '&');
|
||||||
|
//$streamSrc = $event->getStreamSrc(array(
|
||||||
|
//'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&');
|
||||||
|
|
||||||
|
// Modify the row data as needed
|
||||||
|
//$row['imgHtml'] = '<img id="thumbnail' .$event->Id(). '" src="' .$imgSrc. '" alt="Event '.$event->Id().'" width="' .validInt($event->ThumbnailWidth()). '" height="' .validInt($event->ThumbnailHeight()).'" stream_src="' .$streamSrc. '" still_src="' .$imgSrc. '"/>';
|
||||||
|
$row['Name'] = validHtmlStr($row['Name']);
|
||||||
|
$row['Description'] = validHtmlStr($row['Description']);
|
||||||
|
//$row['Archived'] = $row['Archived'] ? translate('Yes') : translate('No');
|
||||||
|
//$row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No');
|
||||||
|
//$row['Cause'] = validHtmlStr($row['Cause']);
|
||||||
|
$row['CreatedOn'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['CreatedOn']));
|
||||||
|
//$row['StartDateTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartDateTime']));
|
||||||
|
//$row['EndDateTime'] = $row['EndDateTime'] ? strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndDateTime'])) : null;
|
||||||
|
//$row['Length'] = gmdate('H:i:s', $row['Length'] );
|
||||||
|
//$row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default';
|
||||||
|
//$row['Notes'] = nl2br(htmlspecialchars($row['Notes']));
|
||||||
|
//$row['DiskSpace'] = human_filesize($event->DiskSpace());
|
||||||
|
$returned_rows[] = $row;
|
||||||
|
} # end foreach row matching search
|
||||||
|
|
||||||
|
$data['rows'] = $returned_rows;
|
||||||
|
|
||||||
|
# totalNotFiltered must equal total, except when either search bar has been used
|
||||||
|
$data['totalNotFiltered'] = count($unfiltered_rows);
|
||||||
|
if ( $search != '' || count($advsearch) ) {
|
||||||
|
$data['total'] = count($filtered_rows);
|
||||||
|
} else {
|
||||||
|
$data['total'] = $data['totalNotFiltered'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
?>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
namespace ZM;
|
||||||
|
require_once('database.php');
|
||||||
|
require_once('Object.php');
|
||||||
|
require_once('Event.php');
|
||||||
|
|
||||||
|
class Snapshot extends ZM_Object {
|
||||||
|
protected static $table = 'Snapshots';
|
||||||
|
protected $defaults = array(
|
||||||
|
'Id' => null,
|
||||||
|
'CreatedBy' => null,
|
||||||
|
'CreatedOn' => 'NOW()',
|
||||||
|
'Name' => '',
|
||||||
|
'Description' => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function find( $parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find(get_class(), $parameters, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function find_one( $parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Event() {
|
||||||
|
return new Event( $this->{'EventId'} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete() {
|
||||||
|
if ( property_exists($this, 'Id') ) {
|
||||||
|
dbQuery('DELETE FROM `Snapshot_Events` WHERE `SnapshotId`=?', array($this->{'Id'}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function EventIds( ) {
|
||||||
|
if ( ! property_exists($this, 'EventIds') ) {
|
||||||
|
$this->{'EventIds'} = dbFetchAll('SELECT `EventId` FROM `Snapshot_Events` WHERE `SnapshotId`=?', 'EventId', array($this->{'Id'}));
|
||||||
|
}
|
||||||
|
return $this->{'EventIds'};
|
||||||
|
}
|
||||||
|
public function Events() {
|
||||||
|
if ( ! property_exists($this, 'Events') ) {
|
||||||
|
$this->{'Events'} = Event::find(array('Id'=>$this->EventIds()));
|
||||||
|
}
|
||||||
|
return $this->{'Events'};
|
||||||
|
}
|
||||||
|
|
||||||
|
} # end class Snapshot
|
||||||
|
|
||||||
|
class Snapshot_Event extends ZM_Object {
|
||||||
|
protected static $table = 'Snapshot_Events';
|
||||||
|
protected $defaults = array(
|
||||||
|
'Id' => null,
|
||||||
|
'EventId' => 0,
|
||||||
|
'SnapshotId' => 0,
|
||||||
|
);
|
||||||
|
public static function find( $parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find(get_class(), $parameters, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function find_one( $parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||||
|
}
|
||||||
|
} # end class Snapshot_Event
|
||||||
|
?>
|
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web action
|
||||||
|
// Copyright (C) 2019 ZoneMinder LLC
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
require_once('includes/Snapshot.php');
|
||||||
|
require_once('includes/Monitor.php');
|
||||||
|
|
||||||
|
|
||||||
|
if ( $action == 'create' ) {
|
||||||
|
if ( ! (isset($_REQUEST['monitor_ids']) and count($_REQUEST['monitor_ids']) > 0 ) ) {
|
||||||
|
ZM\Error('No monitor ids given in snapshot creation request');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$snapshot = new ZM\Snapshot();
|
||||||
|
$snapshot->save(array('CreatedBy'=>$user['Id']));
|
||||||
|
|
||||||
|
foreach ( $_REQUEST['monitor_ids'] as $monitor_id ) {
|
||||||
|
$snapshot_event = new ZM\Snapshot_Event();
|
||||||
|
|
||||||
|
$monitor = new ZM\Monitor($monitor_id);
|
||||||
|
$event_id = $monitor->TriggerOn();
|
||||||
|
ZM\Debug("Have event $event_id for monitor $monitor_id");
|
||||||
|
if ( $event_id ) {
|
||||||
|
$snapshot_event->save(array(
|
||||||
|
'SnapshotId'=>$snapshot->Id(),
|
||||||
|
'EventId'=>$event_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} # end foreach monitor
|
||||||
|
foreach ( $_REQUEST['monitor_ids'] as $monitor_id ) {
|
||||||
|
$monitor = new ZM\Monitor($monitor_id);
|
||||||
|
$monitor->TriggerOff();
|
||||||
|
}
|
||||||
|
$redirect = '?view=snapshot&id='.$snapshot->Id();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event scope actions, view permissions only required
|
||||||
|
if ( isset($_REQUEST['id']) ) {
|
||||||
|
$snapshot = new ZM\Snapshot($_REQUEST['id']);
|
||||||
|
if ( ($action == 'save') ) {
|
||||||
|
if ( canEdit('Events') or $snapshot->CreatedBy() == $user['Id'] ) {
|
||||||
|
|
||||||
|
$changes = $snapshot->changes($_REQUEST['snapshot']);
|
||||||
|
if ( count($changes) ) {
|
||||||
|
$snapshot->save($changes);
|
||||||
|
}
|
||||||
|
$redirect = '?view=snapshots';
|
||||||
|
}
|
||||||
|
} else if ( $action == 'delete' ) {
|
||||||
|
if ( canEdit('Events') ) {
|
||||||
|
$snapshot->delete();
|
||||||
|
$redirect = '?view=snapshots';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end if canEdit(Events)
|
||||||
|
?>
|
|
@ -0,0 +1,17 @@
|
||||||
|
#content {
|
||||||
|
margin: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Name {
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
.Name input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Description {
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
.Description textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
var backBtn = $j('#backBtn');
|
||||||
|
var saveBtn = $j('#saveBtn');
|
||||||
|
var deleteBtn = $j('#deleteBtn');
|
||||||
|
|
||||||
|
// Manage the DELETE CONFIRMATION modal button
|
||||||
|
function manageDelConfirmModalBtns() {
|
||||||
|
document.getElementById('delConfirmBtn').addEventListener('click', function onDelConfirmClick(evt) {
|
||||||
|
if ( !canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
/*
|
||||||
|
$j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eventData.Id)
|
||||||
|
.done(function(data) {
|
||||||
|
streamNext(true);
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the CANCEL modal button
|
||||||
|
document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) {
|
||||||
|
$j('#deleteConfirm').modal('hide');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPage() {
|
||||||
|
|
||||||
|
// enable or disable buttons based on current selection and user rights
|
||||||
|
/*
|
||||||
|
renameBtn.prop('disabled', !canEdit.Events);
|
||||||
|
archiveBtn.prop('disabled', !(!eventData.Archived && canEdit.Events));
|
||||||
|
unarchiveBtn.prop('disabled', !(eventData.Archived && canEdit.Events));
|
||||||
|
*/
|
||||||
|
saveBtn.prop('disabled', !(canEdit.Events || (snapshot.CreatedBy == user.Id) ));
|
||||||
|
/*
|
||||||
|
exportBtn.prop('disabled', !canView.Events);
|
||||||
|
downloadBtn.prop('disabled', !canView.Events);
|
||||||
|
*/
|
||||||
|
deleteBtn.prop('disabled', !canEdit.Events);
|
||||||
|
|
||||||
|
// Don't enable the back button if there is no previous zm page to go back to
|
||||||
|
backBtn.prop('disabled', !document.referrer.length);
|
||||||
|
|
||||||
|
// Manage the BACK button
|
||||||
|
bindButton('#backBtn', 'click', null, function onBackClick(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the REFRESH Button
|
||||||
|
bindButton('#refreshBtn', 'click', null, function onRefreshClick(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
window.location.reload(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the EDIT button
|
||||||
|
bindButton('#saveBtn', 'click', null, function onSaveClick(evt) {
|
||||||
|
/*
|
||||||
|
if ( ! canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
console.log(evt);
|
||||||
|
evt.target.form.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Manage the EXPORT button
|
||||||
|
bindButton('#exportBtn', 'click', null, function onExportClick(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
window.location.assign('?view=export&eids[]='+eventData.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the DOWNLOAD VIDEO button
|
||||||
|
bindButton('#downloadBtn', 'click', null, function onDownloadClick(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=download&eids[]='+eventData.Id)
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('downloadModal', data.html);
|
||||||
|
$j('#downloadModal').modal('show');
|
||||||
|
// Manage the GENERATE DOWNLOAD button
|
||||||
|
$j('#exportButton').click(exportEvent);
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
// Manage the DELETE button
|
||||||
|
bindButton('#deleteBtn', 'click', null, function onDeleteClick(evt) {
|
||||||
|
if ( !canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
if ( ! $j('#deleteConfirm').length ) {
|
||||||
|
// Load the delete confirmation modal into the DOM
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=delconfirm')
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('deleteConfirm', data.html);
|
||||||
|
manageDelConfirmModalBtns();
|
||||||
|
$j('#deleteConfirm').modal('show');
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$j('#deleteConfirm').modal('show');
|
||||||
|
});
|
||||||
|
} // end initPage
|
||||||
|
|
||||||
|
// Kick everything off
|
||||||
|
$j(document).ready(initPage);
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
global $snapshot;
|
||||||
|
?>
|
||||||
|
var snapshot = <?php echo json_encode($snapshot); ?>;
|
||||||
|
|
||||||
|
var eventDataStrings = {
|
||||||
|
Id: '<?php echo translate('EventId') ?>',
|
||||||
|
Name: '<?php echo translate('EventName') ?>',
|
||||||
|
MonitorId: '<?php echo translate('AttrMonitorId') ?>',
|
||||||
|
MonitorName: '<?php echo translate('AttrMonitorName') ?>',
|
||||||
|
Cause: '<?php echo translate('Cause') ?>',
|
||||||
|
StartDateTimeFmt: '<?php echo translate('AttrStartTime') ?>',
|
||||||
|
Length: '<?php echo translate('Duration') ?>',
|
||||||
|
Frames: '<?php echo translate('AttrFrames') ?>',
|
||||||
|
AlarmFrames: '<?php echo translate('AttrAlarmFrames') ?>',
|
||||||
|
TotScore: '<?php echo translate('AttrTotalScore') ?>',
|
||||||
|
AvgScore: '<?php echo translate('AttrAvgScore') ?>',
|
||||||
|
MaxScore: '<?php echo translate('AttrMaxScore') ?>',
|
||||||
|
DiskSpace: '<?php echo translate('DiskSpace') ?>',
|
||||||
|
Storage: '<?php echo translate('Storage') ?>',
|
||||||
|
ArchivedStr: '<?php echo translate('Archived') ?>',
|
||||||
|
EmailedStr: '<?php echo translate('Emailed') ?>'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
//
|
||||||
|
var deleteString = "<?php echo validJsStr(translate('Delete')) ?>";
|
||||||
|
var causeString = "<?php echo validJsStr(translate('AttrCause')) ?>";
|
||||||
|
var WEB_LIST_THUMB_WIDTH = '<?php echo ZM_WEB_LIST_THUMB_WIDTH ?>';
|
||||||
|
var WEB_LIST_THUMB_HEIGHT = '<?php echo ZM_WEB_LIST_THUMB_HEIGHT ?>';
|
|
@ -0,0 +1,312 @@
|
||||||
|
var backBtn = $j('#backBtn');
|
||||||
|
var exportBtn = $j('#exportBtn');
|
||||||
|
var deleteBtn = $j('#deleteBtn');
|
||||||
|
var table = $j('#snapshotTable');
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the format of the json object sent by bootstrap-table
|
||||||
|
|
||||||
|
var params =
|
||||||
|
{
|
||||||
|
"type":"get",
|
||||||
|
"data":
|
||||||
|
{
|
||||||
|
"search":"some search text",
|
||||||
|
"sort":"StartDateTime",
|
||||||
|
"order":"asc",
|
||||||
|
"offset":0,
|
||||||
|
"limit":25
|
||||||
|
"filter":
|
||||||
|
{
|
||||||
|
"Name":"some advanced search text"
|
||||||
|
"StartDateTime":"some more advanced search text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cache":true,
|
||||||
|
"contentType":"application/json",
|
||||||
|
"dataType":"json"
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Called by bootstrap-table to retrieve zm event data
|
||||||
|
function ajaxRequest(params) {
|
||||||
|
if ( params.data && params.data.filter ) {
|
||||||
|
params.data.advsearch = params.data.filter;
|
||||||
|
delete params.data.filter;
|
||||||
|
}
|
||||||
|
$j.getJSON(thisUrl + '?view=request&request=snapshots&task=query', params.data)
|
||||||
|
.done(function(data) {
|
||||||
|
var rows = processRows(data.rows);
|
||||||
|
// rearrange the result into what bootstrap-table expects
|
||||||
|
params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows});
|
||||||
|
})
|
||||||
|
.fail(function(jqXHR) {
|
||||||
|
logAjaxFail(jqXHR);
|
||||||
|
table.bootstrapTable('refresh');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function processRows(rows) {
|
||||||
|
$j.each(rows, function(ndx, row) {
|
||||||
|
|
||||||
|
var id = row.Id;
|
||||||
|
row.Id = '<a href="?view=snapshot&id=' + id + '">' + id + '</a>';
|
||||||
|
row.Name = '<a href="?view=snapshot&id=' + id + '">' + row.Name + '</a>';
|
||||||
|
row.Description = '<a href="?view=snapshot&id=' + id + '">' + row.Description + '</a>';
|
||||||
|
|
||||||
|
//if ( WEB_LIST_THUMBS ) row.Thumbnail = '<a href="?view=snapshot&id=' + row.Id '">' + row.imgHtml + '</a>';
|
||||||
|
});
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the event id's of the selected rows
|
||||||
|
function getIdSelections() {
|
||||||
|
var table = $j('#snapshotTable');
|
||||||
|
|
||||||
|
return $j.map(table.bootstrapTable('getSelections'), function(row) {
|
||||||
|
return row.Id.replace(/(<([^>]+)>)/gi, ''); // strip the html from the element before sending
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a boolen to indicate at least one selected row is archived
|
||||||
|
function getArchivedSelections() {
|
||||||
|
var table = $j('#snapshotTable');
|
||||||
|
var selection = $j.map(table.bootstrapTable('getSelections'), function(row) {
|
||||||
|
return row.Archived;
|
||||||
|
});
|
||||||
|
return selection.includes("Yes");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the Delete Confirmation Modal HTML via Ajax call
|
||||||
|
function getDelConfirmModal() {
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=delconfirm')
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('deleteConfirm', data.html);
|
||||||
|
manageDelConfirmModalBtns();
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage the DELETE CONFIRMATION modal button
|
||||||
|
function manageDelConfirmModalBtns() {
|
||||||
|
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
|
||||||
|
if ( ! canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selections = getIdSelections();
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
$j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+selections.join('&eids[]='))
|
||||||
|
.done( function(data) {
|
||||||
|
$j('#snapshotTable').bootstrapTable('refresh');
|
||||||
|
$j('#deleteConfirm').modal('hide');
|
||||||
|
})
|
||||||
|
.fail( function(jqxhr) {
|
||||||
|
logAjaxFail(jqxhr);
|
||||||
|
$j('#snapshotTable').bootstrapTable('refresh');
|
||||||
|
$j('#deleteConfirm').modal('hide');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the CANCEL modal button
|
||||||
|
document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) {
|
||||||
|
$j('#deleteConfirm').modal('hide');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEventDetailModal(eid) {
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]=' + eid)
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('eventDetailModal', data.html);
|
||||||
|
$j('#eventDetailModal').modal('show');
|
||||||
|
// Manage the Save button
|
||||||
|
$j('#eventDetailSaveBtn').click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
$j('#eventDetailForm').submit();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getObjdetectModal(eid) {
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=objdetect&eid=' + eid)
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('objdetectModal', data.html);
|
||||||
|
$j('#objdetectModal').modal('show');
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPage() {
|
||||||
|
// Remove the thumbnail column from the DOM if thumbnails are off globally
|
||||||
|
if ( !WEB_LIST_THUMBS ) $j('th[data-field="Thumbnail"]').remove();
|
||||||
|
|
||||||
|
// Load the delete confirmation modal into the DOM
|
||||||
|
getDelConfirmModal();
|
||||||
|
|
||||||
|
// Init the bootstrap-table
|
||||||
|
table.bootstrapTable({icons: icons});
|
||||||
|
|
||||||
|
// Hide these columns on first run when no cookie is saved
|
||||||
|
if ( !getCookie("zmEventsTable.bs.table.columns") ) {
|
||||||
|
table.bootstrapTable('hideColumn', 'Archived');
|
||||||
|
table.bootstrapTable('hideColumn', 'Emailed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable or disable buttons based on current selection and user rights
|
||||||
|
table.on('check.bs.table uncheck.bs.table ' +
|
||||||
|
'check-all.bs.table uncheck-all.bs.table',
|
||||||
|
function() {
|
||||||
|
selections = table.bootstrapTable('getSelections');
|
||||||
|
|
||||||
|
viewBtn.prop('disabled', !(selections.length && canView.Events));
|
||||||
|
archiveBtn.prop('disabled', !(selections.length && canEdit.Events));
|
||||||
|
unarchiveBtn.prop('disabled', !(getArchivedSelections()) && canEdit.Events);
|
||||||
|
editBtn.prop('disabled', !(selections.length && canEdit.Events));
|
||||||
|
exportBtn.prop('disabled', !(selections.length && canView.Events));
|
||||||
|
downloadBtn.prop('disabled', !(selections.length && canView.Events));
|
||||||
|
deleteBtn.prop('disabled', !(selections.length && canEdit.Events));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Don't enable the back button if there is no previous zm page to go back to
|
||||||
|
backBtn.prop('disabled', !document.referrer.length);
|
||||||
|
|
||||||
|
// Setup the thumbnail video animation
|
||||||
|
initThumbAnimation();
|
||||||
|
|
||||||
|
// Some toolbar events break the thumbnail animation, so re-init eventlistener
|
||||||
|
table.on('all.bs.table', initThumbAnimation);
|
||||||
|
|
||||||
|
// Manage the BACK button
|
||||||
|
document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
window.history.back();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the REFRESH Button
|
||||||
|
document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
window.location.reload(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Manage the ARCHIVE button
|
||||||
|
document.getElementById("archiveBtn").addEventListener("click", function onArchiveClick(evt) {
|
||||||
|
var selections = getIdSelections();
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
$j.getJSON(thisUrl + '?request=events&task=archive&eids[]='+selections.join('&eids[]='))
|
||||||
|
.done( function(data) {
|
||||||
|
$j('#snapshotTable').bootstrapTable('refresh');
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the UNARCHIVE button
|
||||||
|
document.getElementById("unarchiveBtn").addEventListener("click", function onUnarchiveClick(evt) {
|
||||||
|
if ( ! canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selections = getIdSelections();
|
||||||
|
//console.log(selections);
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
$j.getJSON(thisUrl + '?request=events&task=unarchive&eids[]='+selections.join('&eids[]='))
|
||||||
|
.done( function(data) {
|
||||||
|
$j('#snapshotTable').bootstrapTable('refresh');
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the EDIT button
|
||||||
|
document.getElementById("editBtn").addEventListener("click", function onEditClick(evt) {
|
||||||
|
if ( ! canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selections = getIdSelections();
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]='+selections.join('&eids[]='))
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('eventDetailModal', data.html);
|
||||||
|
$j('#eventDetailModal').modal('show');
|
||||||
|
// Manage the Save button
|
||||||
|
$j('#eventDetailSaveBtn').click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
$j('#eventDetailForm').submit();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the EXPORT button
|
||||||
|
document.getElementById("exportBtn").addEventListener("click", function onExportClick(evt) {
|
||||||
|
var selections = getIdSelections();
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
window.location.assign('?view=export&eids[]='+selections.join('&eids[]='));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the DOWNLOAD VIDEO button
|
||||||
|
document.getElementById("downloadBtn").addEventListener("click", function onDownloadClick(evt) {
|
||||||
|
var selections = getIdSelections();
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
$j.getJSON(thisUrl + '?request=modal&modal=download&eids[]='+selections.join('&eids[]='))
|
||||||
|
.done(function(data) {
|
||||||
|
insertModalHtml('downloadModal', data.html);
|
||||||
|
$j('#downloadModal').modal('show');
|
||||||
|
// Manage the GENERATE DOWNLOAD button
|
||||||
|
$j('#exportButton').click(exportEvent);
|
||||||
|
})
|
||||||
|
.fail(logAjaxFail);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
// Manage the DELETE button
|
||||||
|
document.getElementById("deleteBtn").addEventListener("click", function onDeleteClick(evt) {
|
||||||
|
if ( ! canEdit.Events ) {
|
||||||
|
enoperm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
$j('#deleteConfirm').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update table links each time after new data is loaded
|
||||||
|
table.on('post-body.bs.table', function(data) {
|
||||||
|
// Manage the Object Detection links in the events list
|
||||||
|
$j(".objDetectLink").click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
var eid = $j(this).data('eid');
|
||||||
|
getObjdetectModal(eid);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manage the eventdetail links in the events list
|
||||||
|
$j(".eDetailLink").click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
var eid = $j(this).data('eid');
|
||||||
|
getEventDetailModal(eid);
|
||||||
|
});
|
||||||
|
|
||||||
|
var thumb_ndx = $j('#snapshotTable tr th').filter(function() {
|
||||||
|
return $j(this).text().trim() == 'Thumbnail';
|
||||||
|
}).index();
|
||||||
|
table.find("tr td:nth-child(" + (thumb_ndx+1) + ")").addClass('colThumbnail');
|
||||||
|
});
|
||||||
|
|
||||||
|
table.bootstrapTable('resetSearch');
|
||||||
|
// The table is initially given a hidden style, so now that we are done rendering, show it
|
||||||
|
table.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$j(document).ready(function() {
|
||||||
|
initPage();
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
var confirmDeleteEventsString = "<?php echo addslashes(translate('ConfirmDeleteEvents')) ?>";
|
||||||
|
var archivedString = "<?php echo translate('Archived') ?>";
|
||||||
|
var emailedString = "<?php echo translate('Emailed') ?>";
|
||||||
|
var yesString = "<?php echo translate('Yes') ?>";
|
||||||
|
var noString = "<?php echo translate('No') ?>";
|
||||||
|
var WEB_LIST_THUMBS = <?php echo ZM_WEB_LIST_THUMBS?'true':'false' ?>;
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web snapshot view file, $Date$, $Revision$
|
||||||
|
// Copyright (C) 2001-2008 Philip Coombes
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( !canView('Events') ) {
|
||||||
|
$view = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once('includes/Event.php');
|
||||||
|
require_once('includes/Filter.php');
|
||||||
|
require_once('includes/Snapshot.php');
|
||||||
|
|
||||||
|
$id = isset($_REQUEST['id']) ? validInt($_REQUEST['id']) : null;
|
||||||
|
$snapshot = new ZM\Snapshot($id);
|
||||||
|
|
||||||
|
$monitors = array();
|
||||||
|
if ( $user['MonitorIds'] ) {
|
||||||
|
$monitor_ids = explode(',', $user['MonitorIds']);
|
||||||
|
}
|
||||||
|
xhtmlHeaders(__FILE__, translate('Snapshot').' '.$snapshot->Id());
|
||||||
|
?>
|
||||||
|
<body>
|
||||||
|
<div id="page">
|
||||||
|
<?php echo getNavBarHTML() ?>
|
||||||
|
<?php
|
||||||
|
if ( !$snapshot->Id() ) {
|
||||||
|
echo '<div class="error">Snapshot was not found.</div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!-- BEGIN HEADER -->
|
||||||
|
<form action="?view=snapshot&id=<?php echo $snapshot->Id() ?>" method="post">
|
||||||
|
<input type="hidden" name="action" value="save"/>
|
||||||
|
<div class="d-flex flex-row justify-content-between px-3 py-1">
|
||||||
|
<div id="toolbar">
|
||||||
|
<button id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
|
||||||
|
<button id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
|
||||||
|
<?php if ( $snapshot->Id() ) { ?>
|
||||||
|
<!--
|
||||||
|
<button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Edit') ?>" disabled><i class="fa fa-pencil"></i></button>
|
||||||
|
-->
|
||||||
|
<button id="saveBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Save') ?>"><i class="fa fa-save"></i></button>
|
||||||
|
<!--
|
||||||
|
<button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>"><i class="fa fa-external-link"></i></button>
|
||||||
|
-->
|
||||||
|
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>"><i class="fa fa-trash"></i></button>
|
||||||
|
<?php } // end if snapshot->Id ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><?php echo translate('Snapshot').' '.$snapshot->Id() ?></h2>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-row justify-content-between py-1">
|
||||||
|
<!--
|
||||||
|
<div class="form-group"><label><?php echo translate('Created By') ?></label>
|
||||||
|
-->
|
||||||
|
<div class="form-group CreatedOn"><label><?php echo translate('Created On') ?></label>
|
||||||
|
<?php echo $snapshot->CreatedOn() ?>
|
||||||
|
</div>
|
||||||
|
<div class="form-group Name"><label><?php echo translate('Reference') ?></label>
|
||||||
|
<input type="text" name="snapshot[Name]" value="<?php echo validHtmlStr($snapshot->Name()); ?>"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group Description"><label>
|
||||||
|
<?php echo translate('Notes') ?></label>
|
||||||
|
<textarea name="snapshot[Description]"><?php echo validHtmlStr($snapshot->Description()); ?></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php if ( $snapshot->Id() ) { ?>
|
||||||
|
<!-- BEGIN VIDEO CONTENT ROW -->
|
||||||
|
<div id="content" class="justify-content-center">
|
||||||
|
<?php
|
||||||
|
$events = $snapshot->Events();
|
||||||
|
$width = 100 / ( ( count($events) < 4 ) ? count($events) : 4 ) -1;
|
||||||
|
foreach ( $snapshot->Events() as $event ) {
|
||||||
|
$imgSrc = $event->getThumbnailSrc(array(), '&');
|
||||||
|
echo '<img src="?view=image&eid='.$event->Id().'&fid=snapshot" width="'.$width.'%"/>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div><!--content-->
|
||||||
|
<?php } // end if snapshot->Id() ?>
|
||||||
|
</form>
|
||||||
|
</div><!--page-->
|
||||||
|
<?php xhtmlFooter() ?>
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web snapshots view file
|
||||||
|
// Copyright (C) 2021 Isaac Connor
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( !canView('Events') || (!empty($_REQUEST['execute']) && !canEdit('Events')) ) {
|
||||||
|
$view = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once('includes/Event.php');
|
||||||
|
require_once('includes/Snapshot.php');
|
||||||
|
|
||||||
|
xhtmlHeaders(__FILE__, translate('Snapshots'));
|
||||||
|
getBodyTopHTML();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<?php echo getNavBarHTML() ?>
|
||||||
|
<div id="page" class="container-fluid p-3">
|
||||||
|
<!-- Toolbar button placement and styling handled by bootstrap-tables -->
|
||||||
|
<div id="toolbar">
|
||||||
|
<button id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
|
||||||
|
<button id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
|
||||||
|
<!--<button id="filterBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Filter') ?>"><i class="fa fa-filter"></i></button>-->
|
||||||
|
<!--<button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>" disabled><i class="fa fa-external-link"></i></button>-->
|
||||||
|
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>" disabled><i class="fa fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table styling handled by bootstrap-tables -->
|
||||||
|
<div class="row justify-content-center table-responsive-sm">
|
||||||
|
<table
|
||||||
|
id="snapshotTable"
|
||||||
|
data-locale="<?php echo i18n() ?>"
|
||||||
|
data-side-pagination="server"
|
||||||
|
data-ajax="ajaxRequest"
|
||||||
|
data-pagination="true"
|
||||||
|
data-show-pagination-switch="true"
|
||||||
|
data-page-list="[10, 25, 50, 100, 200, All]"
|
||||||
|
data-search="true"
|
||||||
|
data-cookie="true"
|
||||||
|
data-cookie-id-table="zmSnapshotsTable"
|
||||||
|
data-cookie-expire="2y"
|
||||||
|
data-click-to-select="true"
|
||||||
|
data-remember-order="true"
|
||||||
|
data-show-columns="true"
|
||||||
|
data-show-export="true"
|
||||||
|
data-uncheckAll="true"
|
||||||
|
data-toolbar="#toolbar"
|
||||||
|
data-show-fullscreen="true"
|
||||||
|
data-click-to-select="true"
|
||||||
|
data-maintain-meta-data="true"
|
||||||
|
data-buttons-class="btn btn-normal"
|
||||||
|
data-show-jump-to="true"
|
||||||
|
data-show-refresh="true"
|
||||||
|
class="table-sm table-borderless"
|
||||||
|
style="display:none;"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<!-- Row styling is handled by bootstrap-tables -->
|
||||||
|
<tr>
|
||||||
|
<th data-sortable="false" data-field="toggleCheck" data-checkbox="true"></th>
|
||||||
|
<th data-sortable="true" data-field="Id"><?php echo translate('Id') ?></th>
|
||||||
|
<th data-sortable="true" data-field="Name"><?php echo translate('Reference') ?></th>
|
||||||
|
<th data-sortable="false" data-field="Description"><?php echo translate('Notes') ?></th>
|
||||||
|
<th data-sortable="true" data-field="CreatedOn"><?php echo translate('AttrWhen') ?></th>
|
||||||
|
<th data-sortable="false" data-field="Thumbnail"><?php echo translate('Thumbnail') ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<!-- Row data populated via Ajax -->
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php xhtmlFooter() ?>
|
Loading…
Reference in New Issue