Merge branch 'ZoneMinder:master' into patch-6
commit
49704656b8
|
@ -47,5 +47,5 @@ module.exports = {
|
|||
"php/remove-whitespace": false,
|
||||
"php/remove-empty-line": false,
|
||||
"php/remove-php-lint": false
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,4 +21,4 @@ jobs:
|
|||
- name: Install ESLint
|
||||
run: npm install eslint@8.7.0 eslint-config-google@0.14.0 eslint-plugin-html@6.2.0 eslint-plugin-php-markup@6.0.0
|
||||
- name: Run ESLint
|
||||
run: npx eslint --ext .php,.js .
|
||||
run: npx eslint --ext .js.php,.js .
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE Object_Types (
|
||||
Id int(10) NOT NULL AUTO_INCREMENT,
|
||||
Name varchar(32) UNIQUE,
|
||||
Human TEXT,
|
||||
PRIMARY KEY (Id)
|
||||
);
|
|
@ -1256,6 +1256,7 @@ CREATE TABLE `Events_Tags` (
|
|||
CONSTRAINT `Events_Tags_ibfk_2` FOREIGN KEY (`EventId`) REFERENCES `Events` (`Id`) ON DELETE CASCADE
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
source @PKGDATADIR@/db/Object_Types.sql
|
||||
-- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts.
|
||||
source @PKGDATADIR@/db/triggers.sql
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
%global zmtargetdistro %{?rhel:el%{rhel}}%{!?rhel:fc%{fedora}}
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.37.56
|
||||
Version: 1.37.57
|
||||
Release: 2%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
|
|
|
@ -222,8 +222,8 @@ $fields{model} = undef;
|
|||
Options => undef,
|
||||
User => undef,
|
||||
Pass => undef,
|
||||
Width => undef,
|
||||
Height => undef,
|
||||
Width => 0,
|
||||
Height => 0,
|
||||
Colours => 4,
|
||||
Palette => 0,
|
||||
Orientation => q`'ROTATE_0'`,
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
|
||||
package ZoneMinder::Object;
|
||||
|
||||
use 5.006;
|
||||
|
@ -32,6 +31,7 @@ use Time::HiRes qw{ gettimeofday tv_interval };
|
|||
use Carp qw( cluck );
|
||||
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Object_Type;
|
||||
|
||||
our @ISA = qw(ZoneMinder::Base);
|
||||
|
||||
|
@ -361,7 +361,7 @@ sub set {
|
|||
|
||||
if ( $params ) {
|
||||
foreach my $field ( keys %{$params} ) {
|
||||
$log->debug("field: $field, ".def_or_undef($$self{$field}).' =? param: '.def_or_undef($$params{$field})) if $debug;
|
||||
$log->debug("field: $field, ".def_or_undef($$self{$field}).' =? param: '.def_or_undef($$params{$field})) if $debug or DEBUG_ALL;
|
||||
if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) {
|
||||
# Only make changes to fields that have changed
|
||||
if ( defined $fields{$field} ) {
|
||||
|
@ -886,6 +886,62 @@ sub clone {
|
|||
return $new;
|
||||
} # end sub clone
|
||||
|
||||
sub Object_Type {
|
||||
if ( $_[0]{object_type_id} ) {
|
||||
$_[0]{Object_Type} = new ZoneMinder::Object_Type( $_[0]{object_type_id} );
|
||||
} else {
|
||||
$_[0]{Object_Type} = ZoneMinder::Object_Type->find_one( name=>ref $_[0] );
|
||||
$_[0]{Object_Type} = new ZoneMinder::Object_Type() if ! $_[0]{Object_Type};
|
||||
} # end if
|
||||
return $_[0]{Object_Type};
|
||||
} # end sub Object_Type
|
||||
|
||||
sub object_type {
|
||||
if ( @_ > 1 ) {
|
||||
my $Type = ZoneMinder::Object_Type->find_one( name => $_[1] );
|
||||
if ( ! $Type ) {
|
||||
$Type = new ZoneMinder::Object_Type();
|
||||
$Type->save({ Name=>$_[1], Human=>$_[1] });
|
||||
} # end if
|
||||
$_[0]{object_type} = $Type->Name();
|
||||
$_[0]{object_type_id} = $Type->Id();
|
||||
} # end if
|
||||
if ( ! $_[0]{object_type} ) {
|
||||
$_[0]{object_type} = new ZoneMinder::Object_Type( $_[0]{object_type_id} )->Name();
|
||||
} # end if
|
||||
return $_[0]{object_type};
|
||||
} # end sub object_type
|
||||
|
||||
sub Object {
|
||||
my $self = shift;
|
||||
if ( @_ ) {
|
||||
$self->object_type( ref $_[0] );
|
||||
$$self{object_id} = $_[0]{id};
|
||||
$$self{Object} = $_[0];
|
||||
} # end if
|
||||
my $type = $self->object_type();
|
||||
if ( !$type ) {
|
||||
Error('No type in Object::Object'. $self->to_string()) if ref $self ne 'ZoneMinder::Log';
|
||||
return undef;
|
||||
} # end if
|
||||
my ( $module ) = $type =~ /ZoneMinder::(.*)/;
|
||||
if ( $module ) {
|
||||
eval {
|
||||
require "ZoneMinder/$module.pm";
|
||||
};
|
||||
if ( ! $$self{Object} ) {
|
||||
$_ = $type->new($$self{object_id});
|
||||
Debug( 'Returning object of type ' . ref $_ ) if $debug;
|
||||
$$self{Object} = $_;
|
||||
}
|
||||
return $$self{Object};
|
||||
} else {
|
||||
Error("Unvalid object $type");
|
||||
return new ZoneMinder::Object();
|
||||
}
|
||||
} # end sub Object
|
||||
|
||||
|
||||
sub AUTOLOAD {
|
||||
my $type = ref($_[0]);
|
||||
Carp::cluck("No type in autoload") if ! $type;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use strict;
|
||||
package ZoneMinder::Object_Type;
|
||||
our @ISA = qw( ZoneMinder::Object );
|
||||
|
||||
use vars qw( $debug $table %fields %transforms %defaults $primary_key );
|
||||
|
||||
$debug = 0;
|
||||
$table = 'Object_Types';
|
||||
$primary_key = 'id';
|
||||
%fields = (
|
||||
Id => 'Id',
|
||||
Name => 'Name',
|
||||
Human => 'Human',
|
||||
);
|
||||
%defaults = (
|
||||
);
|
||||
%transforms = (
|
||||
Name => [ 's/^\s+//', 's/\s+$//', 's/\s\s+/ /g' ],
|
||||
Human => [ 's/^\s+//', 's/\s+$//', 's/\s\s+/ /g', 's/^ZoneMinder:://' ],
|
||||
);
|
||||
|
||||
sub Object {
|
||||
if ( $_[0]{Name} ) {
|
||||
my $name = $_[0]{Name};
|
||||
$name =~ s/::/\//g;
|
||||
eval {
|
||||
require $name.'.pm';
|
||||
};
|
||||
$ZoneMinder::log->error("failed requiring $name $@") if $@;
|
||||
return $_[0]{Name}->new($_[1]);
|
||||
}
|
||||
my ($caller, undef, $line) = caller;
|
||||
$ZoneMinder::log->error("Unknown object from $caller:$line");
|
||||
return new ZoneMinder::Object();
|
||||
} # end sub Object
|
||||
|
||||
sub Human {
|
||||
if ( @_ > 1 ) {
|
||||
$_[0]{Human} = $_[1];
|
||||
}
|
||||
if ( ! $_[0]{Human} ) {
|
||||
$_[0]{Human} = $_[0]{Name};
|
||||
$_[0]{Human} =~ s/^ZoneMinder:://;
|
||||
}
|
||||
return $_[0]{Human};
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
|
@ -528,10 +528,20 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got PAN command, to %d,%d", x, y);
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_SCALE :
|
||||
scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
Debug(1, "Got SCALE command, to %d", scale);
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_PREV :
|
||||
Debug(1, "Got PREV command");
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.37.56
|
||||
1.37.57
|
||||
|
|
|
@ -121,6 +121,7 @@ class Event extends ZM_Object {
|
|||
public function StartDateTimeSecs() {
|
||||
return strtotime($this->{'StartDateTime'});
|
||||
}
|
||||
|
||||
public function EndDateTimeSecs() {
|
||||
return strtotime($this->{'EndDateTime'});
|
||||
}
|
||||
|
@ -256,16 +257,19 @@ class Event extends ZM_Object {
|
|||
}
|
||||
|
||||
public function getStreamSrc( $args=array(), $querySep='&' ) {
|
||||
|
||||
$streamSrc = '';
|
||||
$Server = $this->Server();
|
||||
|
||||
# If we are in a multi-port setup, then use the multiport, else by
|
||||
# passing null Server->Url will use the Port set in the Server setting
|
||||
$streamSrc .= $Server->Url(
|
||||
ZM_MIN_STREAMING_PORT ?
|
||||
if ($args['mode'] == 'mp4') { #Downloading a video file. It is possible to reconsider the condition later.
|
||||
#If the port is different from 80, the browser will start watching the video instead of downloading.
|
||||
$port = null;
|
||||
} else {
|
||||
$port = ZM_MIN_STREAMING_PORT ?
|
||||
ZM_MIN_STREAMING_PORT+$this->{'MonitorId'} :
|
||||
null);
|
||||
null;
|
||||
}
|
||||
$streamSrc = $Server->Url($port);
|
||||
|
||||
if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) {
|
||||
$streamSrc .= $Server->PathToIndex();
|
||||
|
@ -677,6 +681,7 @@ class Event extends ZM_Object {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function canEdit($u=null) {
|
||||
global $user;
|
||||
if (!$u) $u=$user;
|
||||
|
@ -840,5 +845,4 @@ class Event extends ZM_Object {
|
|||
} # end sub GenerateVideo
|
||||
|
||||
} # end class
|
||||
|
||||
?>
|
||||
|
|
|
@ -1085,6 +1085,10 @@ class Filter extends ZM_Object {
|
|||
foreach ( $Servers as $server ) {
|
||||
$servers[$server->Id()] = validHtmlStr($server->Name());
|
||||
}
|
||||
$weekdays = array();
|
||||
for ( $i = 0; $i < 7; $i++ ) {
|
||||
$weekdays[$i] = date('D', mktime(12, 0, 0, 1, $i+1, 2001));
|
||||
}
|
||||
$availableTags = array();
|
||||
foreach ( dbFetchAll('SELECT Id, Name FROM Tags ORDER BY LastAssignedDate DESC') AS $tag ) {
|
||||
$availableTags[$tag['Id']] = validHtmlStr($tag['Name']);
|
||||
|
@ -1115,14 +1119,16 @@ class Filter extends ZM_Object {
|
|||
#$html .= '<span>'.htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']).'</span>'.PHP_EOL;
|
||||
|
||||
if ( $term['attr'] == 'Archived' ) {
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $archiveTypes, $term['val'],['class'=>'chosen chosen-full-width']).PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $archiveTypes, $term['val'],['class'=>'chosen chosen-auto-width']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'Tags' ) {
|
||||
$selected = explode(',', $term['val']);
|
||||
// echo '<pre>selected: '; print_r($selected); echo '</pre>';
|
||||
if (count($selected) == 1 and !$selected[0]) {
|
||||
$selected = null;
|
||||
}
|
||||
$options = ['class'=>'term-value-wrapper chosen chosen-full-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('All Tags')];
|
||||
$options = ['class'=>'chosen chosen-auto-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('All Tags')];
|
||||
if (isset($term['cookie'])) {
|
||||
$options['data-cookie'] = $term['cookie'];
|
||||
|
||||
|
@ -1134,7 +1140,9 @@ class Filter extends ZM_Object {
|
|||
// echo '<pre>selected: '; print_r($selected); echo '</pre>';
|
||||
// echo '<pre>options: '; print_r($options); echo '</pre>';
|
||||
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $availableTags, $selected, $options).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $availableTags, $selected, $options).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
// $html .= '<span>'.htmlSelect("filter[Query][terms][$i][val]", array_combine($availableTags,$availableTags), $term['val'],
|
||||
// $options).'</span>'.PHP_EOL;
|
||||
// $html .= '<span>'.htmlSelect("filter[Query][terms][$i][val]", $availableTags, $term['val'], $options).'</span>'.PHP_EOL;
|
||||
|
@ -1147,7 +1155,8 @@ class Filter extends ZM_Object {
|
|||
|
||||
|
||||
} else if ( $term['attr'] == 'DateTime' || $term['attr'] == 'StartDateTime' || $term['attr'] == 'EndDateTime') {
|
||||
$html .= '<span class="term-value-wrapper"><input type="text" class="term-value datetimepicker" name="filter[Query][terms]['.$i.'][val]"';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input type="text" class="term-value datetimepicker" name="filter[Query][terms]['.$i.'][val]"';
|
||||
if (isset($term['id'])) {
|
||||
$html .= ' id="'.$term['id'].'"';
|
||||
} else {
|
||||
|
@ -1160,9 +1169,11 @@ class Filter extends ZM_Object {
|
|||
$html .= ' value="'.(isset($term['val'])?validHtmlStr(str_replace('T', ' ', $term['val'])):'').'"';
|
||||
|
||||
if (!isset($term['placeholder'])) $term['placeholder'] = translate('Attr'.$term['attr']);
|
||||
$html .= ' placeholder="'.$term['placeholder'].'"/></span>'.PHP_EOL;
|
||||
$html .= ' placeholder="'.$term['placeholder'].'"/>'.PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'Date' || $term['attr'] == 'StartDate' || $term['attr'] == 'EndDate' ) {
|
||||
$html .= '<span class="term-value-wrapper"><input type="text" class="term-value datepicker" name="filter[Query][terms]['.$i.'][val]" id="filter[Query][terms]['.$i.'][val]"';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input type="text" class="term-value datepicker" name="filter[Query][terms]['.$i.'][val]" id="filter[Query][terms]['.$i.'][val]"';
|
||||
if (isset($term['cookie'])) {
|
||||
if (!$term['val'] and isset($_COOKIE[$term['cookie']])) $term['val'] = $_COOKIE[$term['cookie']];
|
||||
$html .= ' data-cookie="'.$term['cookie'].'"';
|
||||
|
@ -1170,19 +1181,29 @@ class Filter extends ZM_Object {
|
|||
$html .= ' value="'.(isset($term['val'])?validHtmlStr($term['val']):'').'" placeholder="'.translate('Attr'.$term['attr']).'"';
|
||||
$html .= '/></span>'.PHP_EOL;
|
||||
} else if ( $term['attr'] == 'StartTime' || $term['attr'] == 'EndTime' ) {
|
||||
$html .= '<span class="term-value-wrapper"><input type="text" name="filter[Query][terms]['.$i.'][val]" id="filter[Query][terms]['.$i.'][val]" value="'.(isset($term['val'])?validHtmlStr(str_replace('T', ' ', $term['val'])):'' ).'"/></span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input type="text" name="filter[Query][terms]['.$i.'][val]" id="filter[Query][terms]['.$i.'][val]" value="'.(isset($term['val'])?validHtmlStr(str_replace('T', ' ', $term['val'])):'' ).'"/>'.PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'ExistsInFileSystem' ) {
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $booleanValues, $term['val'], ['class'=>'chosen chosen-full-width']).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $booleanValues, $term['val'], ['class'=>'chosen chosen-auto-width']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
|
||||
} else if ( $term['attr'] == 'Group') {
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", Group::get_dropdown_options(), $term['val'],
|
||||
['class'=>'term-value chosen chosen-full-width',
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", Group::get_dropdown_options(), $term['val'],
|
||||
['class'=>'term-value chosen chosen-auto-width',
|
||||
'multiple'=>'multiple',
|
||||
'data-placeholder'=>translate('All Groups')]).'</span>'.PHP_EOL;
|
||||
'data-placeholder'=>translate('All Groups')]).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'StateId' ) {
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $states, $term['val'], ['class'=>'chosen chosen-full-width']).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $states, $term['val'], ['class'=>'chosen chosen-auto-width']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( strpos($term['attr'], 'Weekday') !== false ) {
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $weekdays, $term['val'], ['class'=>'chosen chosen-full-width']).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $weekdays, $term['val'], ['class'=>'chosen chosen-auto-width']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'Monitor' ) {
|
||||
$monitors = [];
|
||||
foreach (Monitor::find(['Deleted'=>false], ['order'=>'lower(Name)']) as $m) {
|
||||
|
@ -1195,14 +1216,16 @@ class Filter extends ZM_Object {
|
|||
if (count($selected) == 1 and !$selected[0]) {
|
||||
$selected = null;
|
||||
}
|
||||
$options = ['class'=>'term-value chosen chosen-full-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('All Monitors')];
|
||||
$options = ['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('All Monitors')];
|
||||
if (isset($term['cookie'])) {
|
||||
$options['data-cookie'] = $term['cookie'];
|
||||
|
||||
if (!$selected and isset($_COOKIE[$term['cookie']]) and $_COOKIE[$term['cookie']])
|
||||
$selected = explode(',', $_COOKIE[$term['cookie']]);
|
||||
}
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $monitors, $selected, $options).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $monitors, $selected, $options).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'MonitorName' ) {
|
||||
$monitor_names = [];
|
||||
foreach (Monitor::find(['Deleted'=>false], ['order'=>'lower(Name)']) as $m) {
|
||||
|
@ -1210,22 +1233,30 @@ class Filter extends ZM_Object {
|
|||
$monitor_names[$m->Name()] = validHtmlStr($m->Name());
|
||||
}
|
||||
}
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", array_combine($monitor_names,$monitor_names), $term['val'],
|
||||
['class'=>'term-value chosen chosen-full-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('All Monitors')]).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", array_combine($monitor_names,$monitor_names), $term['val'],
|
||||
['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('All Monitors')]).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'ServerId' || $term['attr'] == 'MonitorServerId' || $term['attr'] == 'StorageServerId' || $term['attr'] == 'FilterServerId' ) {
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $servers, $term['val'],
|
||||
['class'=>'term-value chosen chosen-full-width', 'multiple'=>'multiple']).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $servers, $term['val'],
|
||||
['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( ($term['attr'] == 'StorageId') || ($term['attr'] == 'SecondaryStorageId') ) {
|
||||
if (!$storageareas) {
|
||||
$storageareas = array('' => array('Name'=>'NULL Unspecified'), '0' => array('Name'=>'Zero')) + ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
|
||||
}
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val'],
|
||||
['class'=>'term-value chosen chosen-full-width', 'multiple'=>'multiple']).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val'],
|
||||
['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'AlarmedZoneId' ) {
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $zones, $term['val'],
|
||||
['class'=>'term-value chosen chosen-full-width', 'multiple'=>'multiple']).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $zones, $term['val'],
|
||||
['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else if ( $term['attr'] == 'Notes' ) {
|
||||
$attrs = ['class'=>'term-value chosen chosen-full-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('Event Type')];
|
||||
$attrs = ['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('Event Type')];
|
||||
$selected = explode(',', $term['val']);
|
||||
if (count($selected) == 1 and !$selected[0]) {
|
||||
$selected = null;
|
||||
|
@ -1246,13 +1277,19 @@ class Filter extends ZM_Object {
|
|||
'car' => 'Car',
|
||||
'truck' => 'Truck',
|
||||
'vehicle' => 'Vehicle'];
|
||||
$html .= '<span class="term-value-wrapper">'.htmlSelect("filter[Query][terms][$i][val]", $options, $selected, $attrs).'</span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $options, $selected, $attrs).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
} else {
|
||||
#$html .= $term['attr'];
|
||||
$html .= '<span class="term-value-wrapper"><input class="term-value"type="text" name="filter[Query][terms]['.$i.'][val]" value="'.validHtmlStr($term['val']).'"/></span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input class="term-value"type="text" name="filter[Query][terms]['.$i.'][val]" value="'.validHtmlStr($term['val']).'"/>'.PHP_EOL;
|
||||
$html .= '</span>';
|
||||
}
|
||||
} else { # no attr ?
|
||||
$html .= '<span class="term-value-wrapper"><input class="term-value" type="text" name="filter[Query][terms]['.$i.'][val]" value="'.(isset($term['val'])?validHtmlStr($term['val']):'' ).'"/></span>'.PHP_EOL;
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input class="term-value" type="text" name="filter[Query][terms]['.$i.'][val]" value="'.(isset($term['val'])?validHtmlStr($term['val']):'' ).'"/></span>'.PHP_EOL;
|
||||
$html .= '</span>';
|
||||
}
|
||||
|
||||
$html .= '</span>';
|
||||
|
|
|
@ -140,6 +140,11 @@ if ($action == 'save') {
|
|||
if (count($changes)) {
|
||||
// monitor->Id() has a value when the db record exists
|
||||
if ($monitor->Id()) {
|
||||
if ($monitor->Deleted() and ! isset($_REQUEST['newMonitor[Deleted]'])) {
|
||||
# We are saving a new monitor with a specified Id and the Id is used in a deleted record.
|
||||
# Undelete it so that it is visible.
|
||||
$monitor->Deleted(false);
|
||||
}
|
||||
|
||||
# If we change anything that changes the shared mem size, zma can complain. So let's stop first.
|
||||
if ($monitor->Type() != 'WebSite') {
|
||||
|
|
|
@ -339,6 +339,10 @@ function MonitorStream(monitorData) {
|
|||
console.log('onclick');
|
||||
};
|
||||
|
||||
this.onmove = function(evt) {
|
||||
console.log('onmove');
|
||||
};
|
||||
|
||||
this.setup_onclick = function(func) {
|
||||
if (func) {
|
||||
this.onclick = func;
|
||||
|
@ -350,6 +354,17 @@ function MonitorStream(monitorData) {
|
|||
}
|
||||
};
|
||||
|
||||
this.setup_onmove = function(func) {
|
||||
if (func) {
|
||||
this.onmove = func;
|
||||
}
|
||||
if (this.onmove) {
|
||||
const el = this.getFrame();
|
||||
if (!el) return;
|
||||
el.addEventListener('mousemove', this.onmove, false);
|
||||
}
|
||||
};
|
||||
|
||||
this.disable_onclick = function() {
|
||||
const el = this.getElement();
|
||||
if (!el) return;
|
||||
|
|
|
@ -88,9 +88,9 @@ $SLANG = array(
|
|||
'AlarmBrFrames' => 'Кадры<br/>тревоги',
|
||||
'AlarmFrame' => 'Кадр тревоги',
|
||||
'AlarmFrameCount' => 'Число кадров тревоги',
|
||||
'AlarmLimits' => 'Гран. зоны трев.',
|
||||
'AlarmLimits' => 'Границы зоны тревоги',
|
||||
'AlarmMaximumFPS' => 'Макс. к/с при тревоге',
|
||||
'AlarmPx' => 'Пкс трев.',
|
||||
'AlarmPx' => 'Тревожных пикселей',
|
||||
'AlarmRGBUnset' => 'Вы должны установить цвет тревоги (RGB)',
|
||||
'AlarmRefImageBlendPct'=> 'Смешение опорного кадра тревоги, %', // Added - 2015-04-18
|
||||
'Alert' => 'Бдительность',
|
||||
|
@ -175,7 +175,7 @@ $SLANG = array(
|
|||
'BadWidth' => 'Неправильная ширина',
|
||||
'Bandwidth' => 'канал',
|
||||
'BandwidthHead' => 'канал', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing;
|
||||
'BlobPx' => 'Пкс объекта',
|
||||
'BlobPx' => 'Пикселей объекта',
|
||||
'BlobSizes' => 'Размер объектов',
|
||||
'Blobs' => 'Кол-во объектов',
|
||||
'Brightness' => 'Яркость',
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
* Primary look and feel styles
|
||||
*/
|
||||
|
||||
:root {
|
||||
--scrollbarBG: #F1F1F1;
|
||||
--sliderBG: #C1C1C1;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Material Icons";
|
||||
font-style: normal;
|
||||
|
@ -100,14 +105,14 @@ p {
|
|||
font-weight: normal;
|
||||
}
|
||||
|
||||
th {
|
||||
/*
|
||||
th {
|
||||
padding: 3px;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
font-weight: 600;
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
||||
.thead-highlight {
|
||||
background-color:#dfe4ea;
|
||||
|
@ -150,6 +155,14 @@ a.btn,
|
|||
button.btn {
|
||||
line-height: 1;
|
||||
font-size: 18px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
#toolbar .btn-normal {
|
||||
margin-right: 3px;
|
||||
}
|
||||
#rightButtons .btn-normal,
|
||||
#leftButtons .btn-normal {
|
||||
margin-right: 0px;
|
||||
}
|
||||
input, textarea, select, button, .btn-primary {
|
||||
border: 1px #ccc solid;
|
||||
|
@ -162,7 +175,6 @@ input,textarea,select,button,.btn-primary {
|
|||
background-color: #f8f8f8;
|
||||
text-align: left;
|
||||
border-radius:4px;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
input.noborder {
|
||||
|
@ -444,6 +456,10 @@ body.sticky #content {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.hidden-shift {
|
||||
position: absolute !important; left: -999em !important;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -505,7 +521,6 @@ body.sticky #page {
|
|||
|
||||
#header {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
background-color: #34495e;
|
||||
padding: 5px 0px;
|
||||
margin: 0 auto 4px auto;
|
||||
|
@ -736,9 +751,23 @@ ul.nav.nav-pills.flex-column {
|
|||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.chosen-container {
|
||||
#toolbar,
|
||||
.filterTable {
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.controlHeader .chosen-container,
|
||||
#header .chosen-container,
|
||||
#fbpanel .chosen-container,
|
||||
#toolbar .chosen-container {
|
||||
text-align: left;
|
||||
/*min-width: 11em;*/ /* Why ???*/
|
||||
min-width: 11em; /* Makes a nice uniform display */
|
||||
}
|
||||
|
||||
#mfbpanel {
|
||||
width: calc(100% - 25px);
|
||||
float: left;
|
||||
}
|
||||
|
||||
.chosen-container-active .chosen-choices {
|
||||
|
@ -799,14 +828,19 @@ li.search-choice {
|
|||
|
||||
.zoom,
|
||||
.zoom-console {
|
||||
transform-origin: 0% 50%;
|
||||
transform-origin: 0% 00%;
|
||||
transform: scale(5); /* (arbitray zoom value - Note if the zoom is too large, it will go outside of the viewport) */
|
||||
position: sticky;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
#framesTable .zoom {
|
||||
transform-origin: 100% 0%;
|
||||
}
|
||||
|
||||
a.flip {
|
||||
float: right;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#content table.major .colDiskSpace {
|
||||
|
@ -836,8 +870,6 @@ a.flip {
|
|||
padding: 4px 10px 4px 10px;
|
||||
color: white;
|
||||
}
|
||||
#shutdownButton i {
|
||||
}
|
||||
.imageFeed {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
|
@ -890,16 +922,17 @@ a.flip {
|
|||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
.controlHeader {
|
||||
.controlHeader, #fieldsTable {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
justify-content: center;
|
||||
}
|
||||
/* to match chosen text input height */
|
||||
.controlHeader input[type="text"] {
|
||||
height: 29px;
|
||||
padding: 2px 5px 4px 5px;
|
||||
margin-top:0;
|
||||
width: 100%;
|
||||
}
|
||||
@media screen and (max-width:767px) {
|
||||
.controlHeader {
|
||||
|
@ -1000,6 +1033,57 @@ button .material-icons {
|
|||
display: block;
|
||||
}
|
||||
|
||||
input.hasDatepicker {
|
||||
max-width:140px;
|
||||
/* Change scrollbar style */
|
||||
div::-webkit-scrollbar, nav::-webkit-scrollbar, .chosen-results::-webkit-scrollbar {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
div, nav, .chosen-results {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--sliderBG) var(--scrollbarBG);
|
||||
}
|
||||
|
||||
div::-webkit-scrollbar-track, nav::-webkit-scrollbar-track, .chosen-results::-webkit-scrollbar-track {
|
||||
background: var(--scrollbarBG);
|
||||
}
|
||||
|
||||
div::-webkit-scrollbar-thumb, nav::-webkit-scrollbar-thumb, .chosen-results::-webkit-scrollbar-thumb {
|
||||
background-color: var(--sliderBG);
|
||||
border-radius: 6px;
|
||||
border: 3px solid var(--scrollbarBG);
|
||||
}
|
||||
|
||||
.term {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
@media screen and (max-width:500px) {
|
||||
.term {
|
||||
width: 100% !important;
|
||||
flex-direction: row;
|
||||
margin-right: 15px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.term-label-wrapper {
|
||||
text-wrap: nowrap;
|
||||
margin-top: 7px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.term-value-wrapper {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.term-value-wrapper .chosen-container {
|
||||
width: 100% !important;
|
||||
}
|
||||
label {
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
input.hasDatepicker {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,13 +103,13 @@
|
|||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.MonitorNameFilter,
|
||||
/* .MonitorNameFilter,
|
||||
.FunctionFilter,
|
||||
.StatusFilter,
|
||||
.SourceFilter,
|
||||
.MonitorFilter {
|
||||
display: inline-block;
|
||||
}
|
||||
} */
|
||||
form[name="monitorForm"] {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
@ -125,7 +125,8 @@ body.sticky #monitorList {
|
|||
}
|
||||
body.sticky #monitorList thead {
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
top: 0;
|
||||
box-shadow: 0 0px 0, 0 -3px 0 #dfe4ea;
|
||||
}
|
||||
#toolbar,
|
||||
#contentButtons {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
z-index: 10;
|
||||
border: none;
|
||||
border-right: 1px solid black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#alarmCues span {
|
||||
|
@ -192,6 +193,7 @@ height: 100%;
|
|||
*/
|
||||
margin: 0;
|
||||
z-index: 5;
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
|
@ -337,7 +339,7 @@ svg.zones {
|
|||
#indicator {
|
||||
height: 2.75em;
|
||||
position: absolute;
|
||||
border-left: 1px solid blue;
|
||||
border-left: 2px solid blue;
|
||||
margin-top: -1.25em;
|
||||
}
|
||||
.video-js .vjs-text-track-display {
|
||||
|
|
|
@ -43,18 +43,6 @@ input[type="number"].form-control {
|
|||
padding: 5px;
|
||||
}
|
||||
|
||||
#toolbar,
|
||||
.filterTable {
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#toolbar,
|
||||
.filterTable > span{
|
||||
padding-bottom: 5px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
#events {
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
|
@ -85,31 +73,6 @@ body.sticky #eventTable thead {
|
|||
top: -1px;
|
||||
}
|
||||
|
||||
.term {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.term-value, .chosen-container{
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width:500px) {
|
||||
.term {
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
}
|
||||
.term-label-wrapper {
|
||||
text-wrap: nowrap;
|
||||
margin-top: 7px;
|
||||
}
|
||||
.term-value-wrapper {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
label {
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
input.hasDatepicker {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ body.sticky #options {
|
|||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.wrapper-scroll-table {
|
||||
body.sticky .wrapper-scroll-table {
|
||||
position: absolute;
|
||||
margin-right: calc(var(--indent-bootstrap-row) * -1);
|
||||
margin-left: calc(var(--indent-bootstrap-row) * -1);
|
||||
|
|
|
@ -67,8 +67,3 @@
|
|||
stroke: #0000FF;
|
||||
fill: #0000FF;
|
||||
}
|
||||
|
||||
#mfbpanel {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ textarea.form-control-sm {
|
|||
min-height: 3rem;
|
||||
}
|
||||
|
||||
.wrapper-scroll-table {
|
||||
body.sticky .wrapper-scroll-table {
|
||||
position: absolute;
|
||||
margin-right: calc(var(--indent-bootstrap-row) * -1);
|
||||
margin-left: calc(var(--indent-bootstrap-row) * -1);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#header {
|
||||
}
|
||||
|
||||
#header form{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
/* padding-left: 0;
|
||||
padding-right: 0;*/
|
||||
|
|
|
@ -380,7 +380,6 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
}
|
||||
|
||||
#content {
|
||||
width: 96%;
|
||||
margin: 0 auto 8px auto;
|
||||
line-height: 130%;
|
||||
text-align: center;
|
||||
|
@ -399,14 +398,6 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/*
|
||||
#contentDiv {
|
||||
margin: 0 auto 8px;
|
||||
line-height: 140%;
|
||||
text-align: center;
|
||||
}
|
||||
*/
|
||||
|
||||
#content > input[type=submit],
|
||||
#content > input[type=button],
|
||||
#content > button,
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
#header {
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
#layout {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 99%;
|
||||
}
|
||||
#monitors .monitor {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
@ -76,4 +69,3 @@
|
|||
stroke: #0000FF;
|
||||
fill: #0000FF;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
:root {
|
||||
--scrollbarBG: #CFD8DC;
|
||||
--sliderBG: #95AFC0;
|
||||
--alarmBG: #352424;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -59,9 +60,6 @@ img.normal {
|
|||
border: #cccccc solid 1px;
|
||||
}
|
||||
|
||||
hr {
|
||||
}
|
||||
|
||||
ul.tabList li {
|
||||
color: #8f8fc2;
|
||||
border: #8f8fc2 solid 1px;
|
||||
|
@ -205,6 +203,18 @@ input[type=submit]:disabled,
|
|||
background-color: #444444;
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-container .table thead th .both {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC")
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-container .table thead th .asc {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAACQSURBVHja7NKhDcJQFIXhVwNJE6bAMUNN3VkBiUazRxkAdZZAdYrfVeIRGFLMw7RJ02D6gIDoTX5zxadOiDGGTxW+jg0PK8eqsBbDfyp2wHpg7d/CsDZYF6yI1WCtkzCsDOvUQX1HrCwFK7GuI+yGVUzCsFZY9QjqO2Mtp2A7rBbr/qIWa/ubnc3YjP0z9hwA30ri1Ip5X+oAAAAASUVORK5CYII=")
|
||||
}
|
||||
|
||||
.bootstrap-table .fixed-table-container .table thead th .desc {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAACUSURBVHja7NIhDsJAFIThqWkTEk5Rxxlq6uYKSHQ194ADoOYSKE4xDolH1JBiFrNNSFPRbSoIqfjNvORTDyEELBVWbMX+ArO4t9hZfI3UWTykYIXFq8Uw0s3idjIGABYri+0AelqsASAVyyyeB9jFYpaMRbC0eI/Qw+KuvyVjEWwsvi0ev/e5WG7xZHEzC/uJp/0MAFmI4tSJnjqtAAAAAElFTkSuQmCC")
|
||||
}
|
||||
|
||||
.nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover {
|
||||
color: #ffa801;
|
||||
background-color: #333333;
|
||||
|
@ -229,6 +239,7 @@ li.search-choice {
|
|||
background-color: #444444 !important;
|
||||
color: #eee !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
box-shadow: none !important;
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
|
@ -299,4 +310,3 @@ html, body, div, nav, .chosen-results {
|
|||
border-radius: 6px;
|
||||
border: 3px solid var(--scrollbarBG);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
}
|
||||
|
||||
tr.alarm {
|
||||
background-color: #fa8072;
|
||||
background-color: var(--alarmBG);
|
||||
}
|
||||
|
||||
tr.bulk {
|
||||
|
|
|
@ -24,7 +24,7 @@ span.alert {
|
|||
}
|
||||
|
||||
#eventList tr.recent {
|
||||
background-color: #B0E0E6;
|
||||
background-color: var(--alarmBG);
|
||||
}
|
||||
|
||||
#eventList tr.highlight {
|
||||
|
|
|
@ -261,6 +261,22 @@ if ( currentView != 'none' && currentView != 'login' ) {
|
|||
$j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON.
|
||||
|
||||
$j(document).ready(function() {
|
||||
// List of functions that are allowed to be called via the value of an object's DOM attribute.
|
||||
const safeFunc = {
|
||||
drawGraph: function() {
|
||||
if (typeof drawGraph !== 'undefined' && $j.isFunction(drawGraph)) drawGraph();
|
||||
},
|
||||
refreshWindow: function() {
|
||||
if (typeof refreshWindow !== 'undefined' && $j.isFunction(refreshWindow)) refreshWindow();
|
||||
},
|
||||
changeScale: function() {
|
||||
if (typeof changeScale !== 'undefined' && $j.isFunction(changeScale)) changeScale();
|
||||
},
|
||||
applyChosen: function() {
|
||||
if (typeof applyChosen !== 'undefined' && $j.isFunction(applyChosen)) applyChosen();
|
||||
}
|
||||
};
|
||||
|
||||
// Load the Logout and State modals into the dom
|
||||
$j('#logoutButton').click(clickLogout);
|
||||
if ( canEdit.System ) $j('#stateModalBtn').click(getStateModal);
|
||||
|
@ -295,24 +311,44 @@ if ( currentView != 'none' && currentView != 'login' ) {
|
|||
const objIconButton = _this_.find("i");
|
||||
const obj = $j(_this_.attr('data-flip-сontrol-object'));
|
||||
|
||||
obj.removeClass('hidden');
|
||||
if ( obj.is(":visible") ) {
|
||||
if (objIconButton.is('[class="material-icons"]')) { // use material-icons
|
||||
if ( obj.is(":visible") && !obj.hasClass("hidden-shift")) {
|
||||
if (objIconButton.is('[class~="material-icons"]')) { // use material-icons
|
||||
objIconButton.html(objIconButton.attr('data-icon-hidden'));
|
||||
} else if (objIconButton.is('[class^="fa-"]')) { //use Font Awesome
|
||||
} else if (objIconButton.is('[class*="fa-"]')) { //use Font Awesome
|
||||
objIconButton.removeClass(objIconButton.attr('data-icon-visible')).addClass(objIconButton.attr('data-icon-hidden'));
|
||||
}
|
||||
setCookie('zmFilterBarFlip'+_this_.attr('data-flip-сontrol-object'), 'hidden');
|
||||
} else { //hidden
|
||||
if (objIconButton.is('[class="material-icons"]')) { // use material-icons
|
||||
obj.removeClass('hidden-shift').addClass('hidden'); //It is necessary to make the block invisible both for JS and for humans
|
||||
if (objIconButton.is('[class~="material-icons"]')) { // use material-icons
|
||||
objIconButton.html(objIconButton.attr('data-icon-visible'));
|
||||
} else if (objIconButton.is('[class^="fa-"]')) { //use Font Awesome
|
||||
} else if (objIconButton.is('[class*="fa-"]')) { //use Font Awesome
|
||||
objIconButton.removeClass(objIconButton.attr('data-icon-hidden')).addClass(objIconButton.attr('data-icon-visible'));
|
||||
}
|
||||
setCookie('zmFilterBarFlip'+_this_.attr('data-flip-сontrol-object'), 'visible');
|
||||
}
|
||||
|
||||
obj.slideToggle("fast");
|
||||
const nameFuncBefore = _this_.attr('data-flip-сontrol-run-before-func') ? _this_.attr('data-flip-сontrol-run-before-func') : null;
|
||||
const nameFuncAfter = _this_.attr('data-flip-сontrol-run-after-func') ? _this_.attr('data-flip-сontrol-run-after-func') : null;
|
||||
const nameFuncAfterComplet = _this_.attr('data-flip-сontrol-run-after-complet-func') ? _this_.attr('data-flip-сontrol-run-after-complet-func') : null;
|
||||
|
||||
if (nameFuncBefore) {
|
||||
$j.each(nameFuncBefore.split(' '), function(i, nameFunc) {
|
||||
if (typeof safeFunc[nameFunc] === 'function') safeFunc[nameFunc]();
|
||||
});
|
||||
}
|
||||
obj.slideToggle("fast", function() {
|
||||
if (nameFuncAfterComplet) {
|
||||
$j.each(nameFuncAfterComplet.split(' '), function(i, nameFunc) {
|
||||
if (typeof safeFunc[nameFunc] === 'function') safeFunc[nameFunc]();
|
||||
});
|
||||
}
|
||||
});
|
||||
if (nameFuncAfter) {
|
||||
$j.each(nameFuncAfter.split(' '), function(i, nameFunc) {
|
||||
if (typeof safeFunc[nameFunc] === 'function') safeFunc[nameFunc]();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Manage visible filter bar & control button (after document ready)
|
||||
|
@ -327,26 +363,28 @@ if ( currentView != 'none' && currentView != 'login' ) {
|
|||
}
|
||||
|
||||
if (сookie == 'hidden') {
|
||||
if (objIconButton.is('[class="material-icons"]')) { // use material-icons
|
||||
if (objIconButton.is('[class~="material-icons"]')) { // use material-icons
|
||||
objIconButton.html(objIconButton.attr('data-icon-hidden'));
|
||||
} else if (objIconButton.is('[class^="fa-"]')) { //use Font Awesome
|
||||
} else if (objIconButton.is('[class*="fa-"]')) { //use Font Awesome
|
||||
objIconButton.addClass(objIconButton.attr('data-icon-hidden'));
|
||||
}
|
||||
obj.css({'display': 'none'});
|
||||
obj.addClass('hidden-shift'); //To prevent jerking when running the "Chosen" script, it is necessary to make the block visible to JS, but invisible to humans!
|
||||
} else { //no cookies or opened.
|
||||
if (objIconButton.is('[class="material-icons"]')) { // use material-icons
|
||||
if (objIconButton.is('[class~="material-icons"]')) { // use material-icons
|
||||
objIconButton.html(objIconButton.attr('data-icon-visible'));
|
||||
} else if (objIconButton.is('[class^="fa-"]')) { //use Font Awesome
|
||||
} else if (objIconButton.is('[class*="fa-"]')) { //use Font Awesome
|
||||
objIconButton.addClass(objIconButton.attr('data-icon-visible'));
|
||||
}
|
||||
obj.css({'display': 'block'});
|
||||
obj.removeClass('hidden-shift');
|
||||
}
|
||||
});
|
||||
|
||||
// Manage the web console filter bar minimize chevron
|
||||
$j("#mfbflip").click(function() {
|
||||
/*$j("#mfbflip").click(function() {
|
||||
$j("#mfbpanel").slideToggle("slow", function() {
|
||||
if ($j.isFunction('changeScale')) {
|
||||
changeScale();
|
||||
}
|
||||
});
|
||||
var mfbflip = $j("#mfbflip");
|
||||
if ( mfbflip.html() == 'keyboard_arrow_up' ) {
|
||||
|
@ -358,7 +396,7 @@ if ( currentView != 'none' && currentView != 'login' ) {
|
|||
$j('.chosen').chosen("destroy");
|
||||
$j('.chosen').chosen();
|
||||
}
|
||||
});
|
||||
});*/
|
||||
// Autoclose the hamburger button if the end user clicks outside the button
|
||||
$j(document).click(function(event) {
|
||||
var target = $j(event.target);
|
||||
|
@ -1106,9 +1144,9 @@ function applyChosen() {
|
|||
const limit_search_threshold = 10;
|
||||
|
||||
$j('.chosen').chosen('destroy');
|
||||
$j('.chosen').not('.chosen-full-width, .chosen-auto-width').chosen({disable_search_threshold: limit_search_threshold});
|
||||
$j('.chosen.chosen-full-width').chosen({disable_search_threshold: limit_search_threshold, width: "100%"});
|
||||
$j('.chosen.chosen-auto-width').chosen({disable_search_threshold: limit_search_threshold, width: "auto"});
|
||||
$j('.chosen').not('.chosen-full-width, .chosen-auto-width').chosen({disable_search_threshold: limit_search_threshold, search_contains: true});
|
||||
$j('.chosen.chosen-full-width').chosen({disable_search_threshold: limit_search_threshold, search_contains: true, width: "100%"});
|
||||
$j('.chosen.chosen-auto-width').chosen({disable_search_threshold: limit_search_threshold, search_contains: true, width: "auto"});
|
||||
}
|
||||
|
||||
const font = new FontFaceObserver('Material Icons', {weight: 400});
|
||||
|
|
|
@ -61,13 +61,14 @@ if (canView('Groups')) {
|
|||
}
|
||||
|
||||
if (count($GroupsById)) {
|
||||
$html .= '<span id="groupControl"><label>'. translate('Group') .'</label>';
|
||||
$html .= '<span class="term" id="groupControl"><label>'. translate('Group') .'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
# This will end up with the group_id of the deepest selection
|
||||
$group_id = isset($_SESSION['GroupId']) ? $_SESSION['GroupId'] : null;
|
||||
$html .= ZM\Group::get_group_dropdown();
|
||||
$groupSql = ZM\Group::get_group_sql($group_id);
|
||||
$html .= '</span>
|
||||
';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,12 +100,14 @@ if (count($user->unviewableMonitorIds()) ) {
|
|||
$values = array_merge($values, $ids);
|
||||
}
|
||||
|
||||
$html .= '<span class="MonitorNameFilter"><label>'.translate('Name').'</label>';
|
||||
$html .= '<input type="text" name="MonitorName" value="'.(isset($_SESSION['MonitorName'])?validHtmlStr($_SESSION['MonitorName']):'').'" placeholder="text or regular expression"/>';
|
||||
$html .= '<span class="term MonitorNameFilter"><label>'.translate('Name').'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input type="text" name="MonitorName" value="'.(isset($_SESSION['MonitorName'])?validHtmlStr($_SESSION['MonitorName']):'').'" placeholder="text or regular expression"/></span>';
|
||||
$html .= '</span>'.PHP_EOL;
|
||||
|
||||
function addFilterSelect($name, $options) {
|
||||
$html = '<span class="'.$name.'Filter"><label>'.translate($name).'</label>';
|
||||
$html = '<span class="term '.$name.'Filter"><label>'.translate($name).'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect($name.'[]', $options,
|
||||
(isset($_SESSION[$name])?$_SESSION[$name]:''),
|
||||
array(
|
||||
|
@ -114,6 +117,7 @@ function addFilterSelect($name, $options) {
|
|||
'data-placeholder'=>'All',
|
||||
)
|
||||
);
|
||||
$html .= '</span>';
|
||||
$html .= '</span>'.PHP_EOL;
|
||||
return $html;
|
||||
}
|
||||
|
@ -123,7 +127,8 @@ $html .= addFilterSelect('Analysing', array('None'=>translate('None'), 'Always'=
|
|||
$html .= addFilterSelect('Recording', array('None'=>translate('None'), 'OnMotion'=>translate('On Motion'),'Always'=>translate('Always')));
|
||||
|
||||
if ( count($ServersById) > 1 ) {
|
||||
$html .= '<span class="ServerFilter"><label>'. translate('Server').'</label>';
|
||||
$html .= '<span class="term ServerFilter"><label>'. translate('Server').'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect('ServerId[]', $ServersById,
|
||||
(isset($_SESSION['ServerId'])?$_SESSION['ServerId']:''),
|
||||
array(
|
||||
|
@ -133,12 +138,13 @@ if ( count($ServersById) > 1 ) {
|
|||
'data-placeholder'=>'All',
|
||||
)
|
||||
);
|
||||
$html .= '</span>
|
||||
';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>';
|
||||
} # end if have Servers
|
||||
|
||||
if ( count($StorageById) > 1 ) {
|
||||
$html .= '<span class="StorageFilter"><label>'.translate('Storage').'</label>';
|
||||
$html .= '<span class="term StorageFilter"><label>'.translate('Storage').'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect('StorageId[]', $StorageById,
|
||||
(isset($_SESSION['StorageId'])?$_SESSION['StorageId']:''),
|
||||
array(
|
||||
|
@ -147,17 +153,18 @@ if ( count($StorageById) > 1 ) {
|
|||
'multiple'=>'multiple',
|
||||
'data-placeholder'=>'All',
|
||||
) );
|
||||
$html .= '</span>
|
||||
';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>';
|
||||
} # end if have Storage Areas
|
||||
|
||||
$html .= '<span class="StatusFilter"><label>'.translate('Status').'</label>';
|
||||
$html .= '<span class="term StatusFilter"><label>'.translate('Status').'</label>';
|
||||
$status_options = array(
|
||||
'Unknown' => translate('StatusUnknown'),
|
||||
'NotRunning' => translate('StatusNotRunning'),
|
||||
'Running' => translate('StatusRunning'),
|
||||
'Connected' => translate('StatusConnected'),
|
||||
);
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect( 'Status[]', $status_options,
|
||||
( isset($_SESSION['Status']) ? $_SESSION['Status'] : '' ),
|
||||
array(
|
||||
|
@ -166,13 +173,14 @@ $html .= htmlSelect( 'Status[]', $status_options,
|
|||
'multiple'=>'multiple',
|
||||
'data-placeholder'=>'All'
|
||||
) );
|
||||
$html .= '</span>
|
||||
';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>';
|
||||
|
||||
$html .= '<span class="SourceFilter"><label>'.translate('Source').'</label>';
|
||||
$html .= '<span class="term SourceFilter"><label>'.translate('Source').'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= '<input type="text" name="Source" value="'.(isset($_SESSION['Source'])?validHtmlStr($_SESSION['Source']):'').'" placeholder="text or regular expression"/>';
|
||||
$html .= '</span>
|
||||
';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>';
|
||||
|
||||
$sqlAll = 'SELECT M.*, S.*, E.*
|
||||
FROM Monitors AS M
|
||||
|
@ -262,7 +270,8 @@ $html .= '</span>
|
|||
}
|
||||
$displayMonitors[] = $monitors[$i];
|
||||
} # end foreach monitor
|
||||
$html .= '<span class="MonitorFilter"><label>'.translate('Monitor').'</label>';
|
||||
$html .= '<span class="term MonitorFilter"><label>'.translate('Monitor').'</label>';
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect('MonitorId[]', $monitors_dropdown, $selected_monitor_ids,
|
||||
array(
|
||||
'data-on-change'=>'submitThisForm',
|
||||
|
@ -272,8 +281,8 @@ $html .= '</span>
|
|||
) );
|
||||
# Repurpose this variable to be the list of MonitorIds as a result of all the filtering
|
||||
$display_monitor_ids = array_map(function($monitor_row){return $monitor_row['Id'];}, $displayMonitors);
|
||||
$html .= '</span>
|
||||
';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>';
|
||||
echo $html;
|
||||
?>
|
||||
</div>
|
||||
|
|
|
@ -165,7 +165,7 @@ echo $navbar ?>
|
|||
<form name="monitorForm" method="post" action="?view=<?php echo $view; ?>">
|
||||
<input type="hidden" name="action" value=""/>
|
||||
|
||||
<div id="fbpanel" class="filterBar hidden">
|
||||
<div id="fbpanel" class="filterBar hidden-shift">
|
||||
<?php echo $filterbar ?>
|
||||
</div>
|
||||
|
||||
|
@ -351,10 +351,10 @@ for ($monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1) {
|
|||
if (ZM_WEB_LIST_THUMBS && ($monitor['Capturing'] != 'None') && canView('Stream')) {
|
||||
$options = array();
|
||||
|
||||
$ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth();
|
||||
$ratio_factor = $Monitor->ViewWidth() ? $Monitor->ViewHeight() / $Monitor->ViewWidth() : 1;
|
||||
$options['width'] = ZM_WEB_LIST_THUMB_WIDTH;
|
||||
$options['height'] = ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor;
|
||||
$options['scale'] = intval(100*ZM_WEB_LIST_THUMB_WIDTH / $Monitor->ViewWidth());
|
||||
$options['scale'] = $Monitor->ViewWidth() ? intval(100*ZM_WEB_LIST_THUMB_WIDTH / $Monitor->ViewWidth()) : 100;
|
||||
$options['mode'] = 'jpeg';
|
||||
$options['frames'] = 1;
|
||||
|
||||
|
@ -410,7 +410,7 @@ for ($monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1) {
|
|||
echo translate('Analysing') . ': '.translate($monitor['Analysing']).'<br/>';
|
||||
}
|
||||
if ($monitor['Recording'] != 'None') {
|
||||
echo translate('Recording'). ': '.translate($monitor['Recording']).'<br/>';
|
||||
echo translate('Recording') . ': '.translate($monitor['Recording']) . ($monitor['ONVIF_Event_Listener'] ? ' Use ONVIF' : "") . '<br/>';
|
||||
}
|
||||
?><br/>
|
||||
<div class="small text-nowrap text-muted">
|
||||
|
|
|
@ -33,6 +33,14 @@ var wasHidden = false;
|
|||
var availableTags = [];
|
||||
var selectedTags = [];
|
||||
|
||||
var PrevCoordinatFrame = {x: null, y: null};
|
||||
var coordinateMouse = {
|
||||
start_x: null, start_y: null,
|
||||
shiftMouse_x: null, shiftMouse_y: null,
|
||||
shiftMouseForTrigger_x: null, shiftMouseForTrigger_y: null
|
||||
};
|
||||
var leftBtnStatus = {Down: false, UpAfterDown: false};
|
||||
|
||||
$j(document).on("keydown", "", function(e) {
|
||||
e = e || window.event;
|
||||
if (!$j(".tag-input").is(":focus")) {
|
||||
|
@ -71,6 +79,10 @@ $j(document).on("keydown", "", function(e) {
|
|||
$j("#tagInput").focus();
|
||||
showDropdown();
|
||||
}
|
||||
} else if (e.ctrlKey && (e.shift || e.shiftKey)) {
|
||||
//Panning (moving the enlarged frame)
|
||||
} else if (e.shift || e.shiftKey) {
|
||||
//Panning
|
||||
} else {
|
||||
console.log('Modal is not visible: key not implemented: ', e.key, ' keyCode: ', e.keyCode);
|
||||
}
|
||||
|
@ -902,23 +914,101 @@ function handleClick(event) {
|
|||
return; // ignore clicks on control bar
|
||||
}
|
||||
// target should be the img tag
|
||||
if (!(event.ctrlKey && (event.shift || event.shiftKey))) {
|
||||
const target = $j(event.target);
|
||||
|
||||
const width = target.width();
|
||||
const height = target.height();
|
||||
|
||||
const scaleX = parseInt(eventData.Width / width);
|
||||
const scaleY = parseInt(eventData.Height / height);
|
||||
const scaleX = parseFloat(eventData.Width / width);
|
||||
const scaleY = parseFloat(eventData.Height / height);
|
||||
const pos = target.offset();
|
||||
const x = parseInt((event.pageX - pos.left) * scaleX);
|
||||
const y = parseInt((event.pageY - pos.top) * scaleY);
|
||||
|
||||
if (event.shift || event.shiftKey) { // handle both jquery and mootools
|
||||
streamPan(x, y);
|
||||
updatePrevCoordinatFrame(x, y); //Fixing current coordinates after scaling or shifting
|
||||
} else if (event.ctrlKey) { // allow zoom out by control click. useful in fullscreen
|
||||
streamZoomOut();
|
||||
} else {
|
||||
streamZoomIn(x, y);
|
||||
updatePrevCoordinatFrame(x, y); //Fixing current coordinates after scaling or shifting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shiftImgFrame() { //We calculate the coordinates of the image displacement and shift the image
|
||||
let newPosX = parseInt(PrevCoordinatFrame.x - coordinateMouse.shiftMouse_x);
|
||||
let newPosY = parseInt(PrevCoordinatFrame.y - coordinateMouse.shiftMouse_y);
|
||||
|
||||
if (newPosX < 0) newPosX = 0;
|
||||
if (newPosX > eventData.Width) newPosX = eventData.Width;
|
||||
if (newPosY < 0) newPosY = 0;
|
||||
if (newPosY > eventData.Height) newPosY = eventData.Height;
|
||||
|
||||
streamPan(newPosX, newPosY);
|
||||
updatePrevCoordinatFrame(newPosX, newPosY);
|
||||
coordinateMouse.shiftMouseForTrigger_x = coordinateMouse.shiftMouseForTrigger_y = 0;
|
||||
}
|
||||
|
||||
function updateCoordinateMouse(x, y) { //We fix the coordinates when pressing the left mouse button
|
||||
coordinateMouse.start_x = x;
|
||||
coordinateMouse.start_y = y;
|
||||
}
|
||||
|
||||
function updatePrevCoordinatFrame(x, y) { //Update the Frame's current coordinates
|
||||
PrevCoordinatFrame.x = x;
|
||||
PrevCoordinatFrame.y = y;
|
||||
}
|
||||
|
||||
function getCoordinateMouse(event) { //We get the current cursor coordinates taking into account the scale relative to the frame size.
|
||||
const target = $j(event.target);
|
||||
|
||||
const scaleX = parseFloat(eventData.Width / target.width());
|
||||
const scaleY = parseFloat(eventData.Height / target.height());
|
||||
const pos = target.offset();
|
||||
|
||||
return {x: parseInt((event.pageX - pos.left) * scaleX), y: parseInt((event.pageY - pos.top) * scaleY)}; //The point of the mouse click relative to the dimensions of the real frame.
|
||||
}
|
||||
|
||||
function handleMove(event) {
|
||||
if (event.ctrlKey && (event.shift || event.shiftKey)) {
|
||||
document.ondragstart = function() {
|
||||
return false;
|
||||
}; //Allow drag and drop
|
||||
} else {
|
||||
document.ondragstart = function() {}; //Prevent drag and drop
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftBtnStatus.Down) { //The left button was previously pressed and is now being held. Processing movement with a pressed button.
|
||||
var {x, y} = getCoordinateMouse(event);
|
||||
const k = Math.log(2.72) / Math.log(parseFloat($j('#zoomValue').html())) - 0.3; //Necessary for correctly shifting the image in accordance with the scaling proportions
|
||||
|
||||
coordinateMouse.shiftMouse_x = parseInt((x - coordinateMouse.start_x) * k);
|
||||
coordinateMouse.shiftMouse_y = parseInt((y - coordinateMouse.start_y) * k);
|
||||
|
||||
coordinateMouse.shiftMouseForTrigger_x = Math.abs(parseInt(x - coordinateMouse.start_x));
|
||||
coordinateMouse.shiftMouseForTrigger_y = Math.abs(parseInt(y - coordinateMouse.start_y));
|
||||
}
|
||||
if (event.buttons == 1 && leftBtnStatus.Down != true) { //Start of pressing left button
|
||||
const {x, y} = getCoordinateMouse(event);
|
||||
|
||||
updateCoordinateMouse(x, y);
|
||||
leftBtnStatus.Down = true;
|
||||
} else if (event.buttons == 0 && leftBtnStatus.Down == true) { //Up left button after pressed
|
||||
leftBtnStatus.Down = false;
|
||||
leftBtnStatus.UpAfterDown = true;
|
||||
}
|
||||
|
||||
if ((leftBtnStatus.UpAfterDown) || //The left button was raised or the cursor was moved more than 30 pixels relative to the actual size of the image
|
||||
((coordinateMouse.shiftMouseForTrigger_x > 30) && leftBtnStatus.Down) ||
|
||||
((coordinateMouse.shiftMouseForTrigger_y > 30) && leftBtnStatus.Down)) {
|
||||
//We perform frame shift
|
||||
shiftImgFrame();
|
||||
updateCoordinateMouse(x, y);
|
||||
leftBtnStatus.UpAfterDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1084,6 +1174,9 @@ function initPage() {
|
|||
vid.on('click', function(event) {
|
||||
handleClick(event);
|
||||
});
|
||||
vid.on('mousemove', function(event) { // It is not clear whether it is necessary...
|
||||
handleMove(event);
|
||||
});
|
||||
vid.on('volumechange', function() {
|
||||
setCookie('volume', vid.volume());
|
||||
});
|
||||
|
@ -1118,6 +1211,9 @@ function initPage() {
|
|||
$j(streamImg).click(function(event) {
|
||||
handleClick(event);
|
||||
});
|
||||
$j(streamImg).mousemove(function(event) {
|
||||
handleMove(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
} // end if videojs or mjpeg stream
|
||||
|
|
|
@ -16,6 +16,14 @@ var classMonitorW_SB_L = 'col-sm-9'; /* id="wrapperMonitor" ONLY WITH LEFT */
|
|||
var classMonitorW_SB_R = 'col-sm-10'; /* id="wrapperMonitor" ONLY WITH RIGHT */
|
||||
var classMonitorWO_SB = 'col-sm-12'; /* id="wrapperMonitor" MAXIMUM width */
|
||||
|
||||
var PrevCoordinatFrame = {x: null, y: null};
|
||||
var coordinateMouse = {
|
||||
start_x: null, start_y: null,
|
||||
shiftMouse_x: null, shiftMouse_y: null,
|
||||
shiftMouseForTrigger_x: null, shiftMouseForTrigger_y: null
|
||||
};
|
||||
var leftBtnStatus = {Down: false, UpAfterDown: false};
|
||||
|
||||
/*
|
||||
This is the format of the json object sent by bootstrap-table
|
||||
|
||||
|
@ -593,13 +601,14 @@ function fetchImage(streamImage) {
|
|||
}
|
||||
|
||||
function handleClick(event) {
|
||||
if (!(event.ctrlKey && (event.shift || event.shiftKey))) {
|
||||
// target should be the img tag
|
||||
const target = $j(event.target);
|
||||
const width = target.width();
|
||||
const height = target.height();
|
||||
|
||||
const scaleX = parseInt(monitorWidth / width);
|
||||
const scaleY = parseInt(monitorHeight / height);
|
||||
const scaleX = parseFloat(monitorWidth / width);
|
||||
const scaleY = parseFloat(monitorHeight / height);
|
||||
const pos = target.offset();
|
||||
const x = parseInt((event.pageX - pos.left) * scaleX);
|
||||
const y = parseInt((event.pageY - pos.top) * scaleY);
|
||||
|
@ -607,15 +616,92 @@ function handleClick(event) {
|
|||
if (showMode == 'events' || !imageControlMode) {
|
||||
if (event.shift || event.shiftKey) {
|
||||
streamCmdPan(x, y);
|
||||
updatePrevCoordinatFrame(x, y); //Fixing current coordinates after scaling or shifting
|
||||
} else if (event.ctrlKey) {
|
||||
streamCmdZoomOut();
|
||||
} else {
|
||||
streamCmdZoomIn(x, y);
|
||||
updatePrevCoordinatFrame(x, y); //Fixing current coordinates after scaling or shifting
|
||||
}
|
||||
} else {
|
||||
controlCmdImage(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shiftImgFrame() { //We calculate the coordinates of the image displacement and shift the image
|
||||
let newPosX = parseInt(PrevCoordinatFrame.x - coordinateMouse.shiftMouse_x);
|
||||
let newPosY = parseInt(PrevCoordinatFrame.y - coordinateMouse.shiftMouse_y);
|
||||
|
||||
if (newPosX < 0) newPosX = 0;
|
||||
if (newPosX > monitorWidth) newPosX = monitorWidth;
|
||||
if (newPosY < 0) newPosY = 0;
|
||||
if (newPosY > monitorHeight) newPosY = monitorHeight;
|
||||
|
||||
streamCmdPan(newPosX, newPosY);
|
||||
updatePrevCoordinatFrame(newPosX, newPosY);
|
||||
coordinateMouse.shiftMouseForTrigger_x = coordinateMouse.shiftMouseForTrigger_y = 0;
|
||||
}
|
||||
|
||||
function updateCoordinateMouse(x, y) { //We fix the coordinates when pressing the left mouse button
|
||||
coordinateMouse.start_x = x;
|
||||
coordinateMouse.start_y = y;
|
||||
}
|
||||
|
||||
function updatePrevCoordinatFrame(x, y) { //Update the Frame's current coordinates
|
||||
PrevCoordinatFrame.x = x;
|
||||
PrevCoordinatFrame.y = y;
|
||||
}
|
||||
|
||||
function getCoordinateMouse(event) { //We get the current cursor coordinates taking into account the scale relative to the frame size.
|
||||
const target = $j(event.target);
|
||||
|
||||
const scaleX = parseFloat(monitorWidth / target.width());
|
||||
const scaleY = parseFloat(monitorHeight / target.height());
|
||||
const pos = target.offset();
|
||||
|
||||
return {x: parseInt((event.pageX - pos.left) * scaleX), y: parseInt((event.pageY - pos.top) * scaleY)}; //The point of the mouse click relative to the dimensions of the real frame.
|
||||
}
|
||||
|
||||
function handleMove(event) {
|
||||
if (event.ctrlKey && event.shiftKey) {
|
||||
document.ondragstart = function() {
|
||||
return false;
|
||||
}; //Allow drag and drop
|
||||
} else {
|
||||
document.ondragstart = function() {}; //Prevent drag and drop
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftBtnStatus.Down) { //The left button was previously pressed and is now being held. Processing movement with a pressed button.
|
||||
var {x, y} = getCoordinateMouse(event);
|
||||
const k = Math.log(2.72) / Math.log(parseFloat($j('#zoomValue'+monitorId).html())) - 0.3; //Necessary for correctly shifting the image in accordance with the scaling proportions
|
||||
|
||||
coordinateMouse.shiftMouse_x = parseInt((x - coordinateMouse.start_x) * k);
|
||||
coordinateMouse.shiftMouse_y = parseInt((y - coordinateMouse.start_y) * k);
|
||||
|
||||
coordinateMouse.shiftMouseForTrigger_x = Math.abs(parseInt(x - coordinateMouse.start_x));
|
||||
coordinateMouse.shiftMouseForTrigger_y = Math.abs(parseInt(y - coordinateMouse.start_y));
|
||||
}
|
||||
if (event.buttons == 1 && leftBtnStatus.Down != true) { //Start of pressing left button
|
||||
const {x, y} = getCoordinateMouse(event);
|
||||
|
||||
updateCoordinateMouse(x, y);
|
||||
leftBtnStatus.Down = true;
|
||||
} else if (event.buttons == 0 && leftBtnStatus.Down == true) { //Up left button after pressed
|
||||
leftBtnStatus.Down = false;
|
||||
leftBtnStatus.UpAfterDown = true;
|
||||
}
|
||||
|
||||
if ((leftBtnStatus.UpAfterDown) || //The left button was raised or the cursor was moved more than 30 pixels relative to the actual size of the image
|
||||
((coordinateMouse.shiftMouseForTrigger_x > 30) && leftBtnStatus.Down) ||
|
||||
((coordinateMouse.shiftMouseForTrigger_y > 30) && leftBtnStatus.Down)) {
|
||||
//We perform frame shift
|
||||
shiftImgFrame();
|
||||
updateCoordinateMouse(x, y);
|
||||
leftBtnStatus.UpAfterDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
function zoomOutClick(event) {
|
||||
if (event.ctrlKey) {
|
||||
|
@ -800,6 +886,7 @@ function initPage() {
|
|||
monitorStream.setup_onclick(fetchImage);
|
||||
} else {
|
||||
monitorStream.setup_onclick(handleClick);
|
||||
monitorStream.setup_onmove(handleMove);
|
||||
}
|
||||
monitorStream.setup_onpause(onPause);
|
||||
monitorStream.setup_onplay(onPlay);
|
||||
|
|
|
@ -39,46 +39,58 @@ getBodyTopHTML();
|
|||
<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>
|
||||
<span class="ComponentFilter">
|
||||
<div class="controlHeader">
|
||||
<span class="term ComponentFilter">
|
||||
<label><?php echo translate('Component') ?></label>
|
||||
<?php
|
||||
$components = dbFetchAll('SELECT DISTINCT Component FROM Logs ORDER BY Component', 'Component');
|
||||
ZM\Debug(print_r($components, true));
|
||||
$options = [''=>translate('All')] + array_combine($components, $components);
|
||||
ZM\Debug(print_r($options, true));
|
||||
echo htmlSelect('filterComponent', $options, '', array('id'=>'filterComponent'));
|
||||
echo '<span class="term-value-wrapper">';
|
||||
echo htmlSelect('filterComponent', $options, '', array('id'=>'filterComponent', 'class'=>'chosen'));
|
||||
echo '</span>';
|
||||
?>
|
||||
</span>
|
||||
<?php if (count($Servers)>1) { ?>
|
||||
<span class="ServerFilter">
|
||||
<span class="term ServerFilter">
|
||||
<label><?php echo translate('Server') ?></label>
|
||||
<?php
|
||||
$ServersById = array(''=>translate('All')) + array_to_hash_by_key('Id', $Servers);
|
||||
echo htmlSelect('filterServerId', $ServersById, '', array('id'=>'filterServerId'));
|
||||
echo '<span class="term-value-wrapper">';
|
||||
echo htmlSelect('filterServerId', $ServersById, '', array('id'=>'filterServerId', 'class'=>'chosen'));
|
||||
echo '</span>';
|
||||
?>
|
||||
</span>
|
||||
<?php } ?>
|
||||
<span class="LevelFilter">
|
||||
<span class="term LevelFilter">
|
||||
<label><?php echo translate('Level') ?></label>
|
||||
<?php
|
||||
$levels = array(''=>translate('All'));
|
||||
foreach (array_values(ZM\Logger::$codes) as $level) {
|
||||
$levels[$level] = $level;
|
||||
}
|
||||
echo '<span class="term-value-wrapper">';
|
||||
echo htmlSelect('filterLevel', $levels,
|
||||
(isset($_SESSION['ZM_LOG_FILTER_LEVEL']) ? $_SESSION['ZM_LOG_FILTER_LEVEL'] : ''),
|
||||
array('data-on-change'=>'filterLog', 'id'=>'filterLevel'));
|
||||
array('data-on-change'=>'filterLog', 'id'=>'filterLevel', 'class'=>'chosen'));
|
||||
#array('class'=>'form-control chosen', 'data-on-change'=>'filterLog'));
|
||||
echo '</span>';
|
||||
?>
|
||||
</span>
|
||||
<span class="StartDateTimeFilter">
|
||||
<span class="term StartDateTimeFilter">
|
||||
<label><?php echo translate('Start Date/Time') ?></label>
|
||||
<span class="term-value-wrapper">
|
||||
<input type="text" name="filterStartDateTime" id="filterStartDateTime" value=""/>
|
||||
</span>
|
||||
<span class="EndDateTimeFilter">
|
||||
</span>
|
||||
<span class="term EndDateTimeFilter">
|
||||
<label><?php echo translate('End Date/Time') ?></label>
|
||||
<span class="term-value-wrapper">
|
||||
<input type="text" name="filterEndDateTime" id="filterEndDateTime" value=""/>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div><!--toolbar-->
|
||||
|
||||
<table
|
||||
|
|
|
@ -190,10 +190,13 @@ echo getNavBarHTML();
|
|||
<div id="page">
|
||||
<div id="header">
|
||||
<?php
|
||||
$html = '';
|
||||
$flip = ( (!isset($_COOKIE['zmMonitorFilterBarFlip'])) or ($_COOKIE['zmMonitorFilterBarFlip'] == 'down')) ? 'up' : 'down';
|
||||
$html .= '<a class="flip" href="#"><i id="mfbflip" class="material-icons md-18">keyboard_arrow_' .$flip. '</i></a>'.PHP_EOL;
|
||||
$html .= '<div class="container-fluid" id="mfbpanel"'.( ( $flip == 'down' ) ? ' style="display:none;"' : '' ) .'>'.PHP_EOL;
|
||||
$html = '<a class="flip" href="#"
|
||||
data-flip-сontrol-object="#mfbpanel"
|
||||
data-flip-сontrol-run-after-func="applyChosen"
|
||||
data-flip-сontrol-run-after-complet-func="changeScale">
|
||||
<i id="mfbflip" class="material-icons md-18" data-icon-visible="filter_alt_off" data-icon-hidden="filter_alt"></i>
|
||||
</a>'.PHP_EOL;
|
||||
$html .= '<div id="mfbpanel" class="hidden-shift container-fluid">'.PHP_EOL;
|
||||
echo $html;
|
||||
?>
|
||||
<div id="headerButtons">
|
||||
|
|
|
@ -271,10 +271,13 @@ getBodyTopHTML();
|
|||
<input type="hidden" name="view" value="montagereview"/>
|
||||
<div id="header">
|
||||
<?php
|
||||
$html = '';
|
||||
$flip = ( (!isset($_COOKIE['zmMonitorFilterBarFlip'])) or ($_COOKIE['zmMonitorFilterBarFlip'] == 'down')) ? 'up' : 'down';
|
||||
$html .= '<a class="flip" href="#"><i id="mfbflip" class="material-icons md-18">keyboard_arrow_' .$flip. '</i></a>'.PHP_EOL;
|
||||
$html .= '<div class="container-fluid" id="mfbpanel"'.( ( $flip == 'down' ) ? ' style="display:none;"' : '' ) .'>'.PHP_EOL;
|
||||
$html = '<a class="flip" href="#"
|
||||
data-flip-сontrol-object="#mfbpanel"
|
||||
data-flip-сontrol-run-after-func="applyChosen drawGraph"
|
||||
data-flip-сontrol-run-after-complet-func="changeScale">
|
||||
<i id="mfbflip" class="material-icons md-18" data-icon-visible="filter_alt_off" data-icon-hidden="filter_alt"></i>
|
||||
</a>'.PHP_EOL;
|
||||
$html .= '<div id="mfbpanel" class="hidden-shift container-fluid">'.PHP_EOL;
|
||||
echo $html;
|
||||
?>
|
||||
<?php echo $filter_bar ?>
|
||||
|
@ -324,8 +327,11 @@ if (count($filter->terms())) {
|
|||
?>
|
||||
<button type="button" id="downloadVideo" data-on-click="click_download"><?php echo translate('Download Video') ?></button>
|
||||
<?php } // end if !live ?>
|
||||
<button type="button" id="collapse" data-flip-сontrol-object="#timelinediv" data-flip-сontrol-run-after-func="drawGraph"> <!-- OR run redrawScreen? -->
|
||||
<i class="material-icons" data-icon-visible="history_toggle_off" data-icon-hidden="schedule"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="timelinediv">
|
||||
<div id="timelinediv" class="hidden-shift">
|
||||
<canvas id="timeline"></canvas>
|
||||
<span id="scrubleft"></span>
|
||||
<span id="scrubright"></span>
|
||||
|
|
|
@ -194,10 +194,13 @@ echo getNavBarHTML() ?>
|
|||
<div id="page">
|
||||
<div id="header">
|
||||
<?php
|
||||
$html = '';
|
||||
$flip = ( (!isset($_COOKIE['zmMonitorFilterBarFlip'])) or ($_COOKIE['zmMonitorFilterBarFlip'] == 'down')) ? 'up' : 'down';
|
||||
$html .= '<a class="flip" href="#"><i id="mfbflip" class="material-icons md-18">keyboard_arrow_' .$flip. '</i></a>'.PHP_EOL;
|
||||
$html .= '<div class="container-fluid" id="mfbpanel"'.( ( $flip == 'down' ) ? ' style="display:none;"' : '' ) .'>'.PHP_EOL;
|
||||
$html = '<a class="flip" href="#"
|
||||
data-flip-сontrol-object="#mfbpanel"
|
||||
data-flip-сontrol-run-after-func="applyChosen"
|
||||
data-flip-сontrol-run-after-complet-func="changeScale">
|
||||
<i id="mfbflip" class="material-icons md-18" data-icon-visible="filter_alt_off" data-icon-hidden="filter_alt"></i>
|
||||
</a>'.PHP_EOL;
|
||||
$html .= '<div id="mfbpanel" class="hidden-shift container-fluid">'.PHP_EOL;
|
||||
echo $html;
|
||||
?>
|
||||
<div class="controlHeader">
|
||||
|
@ -420,7 +423,7 @@ if ( canView('Events') && ($monitor->Type() != 'WebSite') ) {
|
|||
data-show-refresh="true"
|
||||
class="table-sm table-borderless"
|
||||
>
|
||||
<thead>
|
||||
<thead class="thead-highlight">
|
||||
<!-- Row styling is handled by bootstrap-tables -->
|
||||
<tr>
|
||||
<th data-sortable="false" data-field="Delete"><?php echo translate('Delete') ?></th>
|
||||
|
|
Loading…
Reference in New Issue