mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-05-24 14:36:09 -04:00
Merge pull request #4311 from IgorA100/patch-617239
Feat: Added left side menu
This commit is contained in:
@@ -1147,6 +1147,7 @@ class Filter extends ZM_Object {
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $availableTags, $selected, $options).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
// $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;
|
||||
@@ -1192,7 +1193,7 @@ class Filter extends ZM_Object {
|
||||
$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>';
|
||||
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'Group') {
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", Group::get_dropdown_options(), $term['val'],
|
||||
@@ -1200,14 +1201,17 @@ class Filter extends ZM_Object {
|
||||
'multiple'=>'multiple',
|
||||
'data-placeholder'=>translate('All Groups')]).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'StateId' ) {
|
||||
$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>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( strpos($term['attr'], 'Weekday') !== false ) {
|
||||
$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>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'Monitor' ) {
|
||||
$monitors = [];
|
||||
foreach (Monitor::find(['Deleted'=>false], ['order'=>'lower(Name)']) as $m) {
|
||||
@@ -1230,6 +1234,7 @@ class Filter extends ZM_Object {
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $monitors, $selected, $options).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'MonitorName' ) {
|
||||
$monitor_names = [];
|
||||
foreach (Monitor::find(['Deleted'=>false], ['order'=>'lower(Name)']) as $m) {
|
||||
@@ -1241,11 +1246,13 @@ class Filter extends ZM_Object {
|
||||
$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>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'ServerId' || $term['attr'] == 'MonitorServerId' || $term['attr'] == 'StorageServerId' || $term['attr'] == 'FilterServerId' ) {
|
||||
$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>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} 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');
|
||||
@@ -1254,11 +1261,13 @@ class Filter extends ZM_Object {
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val'],
|
||||
['class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple']).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'AlarmedZoneId' ) {
|
||||
$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>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else if ( $term['attr'] == 'Notes' ) {
|
||||
$attrs = ['id'=>'filterNotes', 'class'=>'term-value chosen chosen-auto-width', 'multiple'=>'multiple', 'data-placeholder'=>translate('Event Type')];
|
||||
$selected = explode(',', $term['val']);
|
||||
@@ -1286,6 +1295,7 @@ class Filter extends ZM_Object {
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
$html .= htmlSelect("filter[Query][terms][$i][val]", $options, $selected, $attrs).PHP_EOL;
|
||||
$html .= '</span>';
|
||||
$html .= $this->addButtonForFilterSelect("filter[Query][terms][$i][val]");
|
||||
} else {
|
||||
#$html .= $term['attr'];
|
||||
$html .= '<span class="term-value-wrapper">';
|
||||
@@ -1374,5 +1384,19 @@ class Filter extends ZM_Object {
|
||||
return false;
|
||||
}
|
||||
|
||||
function addButtonForFilterSelect($nameSelect) {
|
||||
if (isset($_COOKIE['zmUseOldMenuView']) and $_COOKIE["zmUseOldMenuView"] === 'true') {
|
||||
$html = '';
|
||||
} else {
|
||||
$html = PHP_EOL . '
|
||||
<span class="btn-term-remove-all">
|
||||
<button type="button" name="deleteBtn" data-on-click-this="resetSelectElement" data-select-target="'.$nameSelect.'">
|
||||
<i class="material-icons">clear</i>
|
||||
<span class="text"></span>
|
||||
</button>
|
||||
</span>' . PHP_EOL;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
} # end class Filter
|
||||
?>
|
||||
|
||||
550
web/skins/classic/assets/mb.extruder/inc/mbExtruder.js
Normal file
550
web/skins/classic/assets/mb.extruder/inc/mbExtruder.js
Normal file
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* jquery.mb.components
|
||||
* file: mbExtruder.js
|
||||
*
|
||||
* Copyright (c) 2001-2014. Matteo Bicocchi (Pupunzi);
|
||||
* Open lab srl, Firenze - Italy
|
||||
* email: matteo@open-lab.com
|
||||
* site: http://pupunzi.com
|
||||
* blog: http://pupunzi.open-lab.com
|
||||
* http://open-lab.com
|
||||
*
|
||||
* Licences: MIT, GPL
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* last modified: 08/05/14 20.00
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
document.extruder=new Object();
|
||||
document.extruder.left = 0;
|
||||
document.extruder.top = 0;
|
||||
document.extruder.bottom = 0;
|
||||
document.extruder.right = 0;
|
||||
document.extruder.idx=0;
|
||||
|
||||
$.mbExtruder= {
|
||||
author:"Matteo Bicocchi & IgorA100",
|
||||
version:"2.6.0",
|
||||
defaults:{
|
||||
width:350,
|
||||
noFlap:false,
|
||||
positionFixed:true,
|
||||
/*+*/ selectorResponsiveBlock: null,
|
||||
/*+*/ attachToParentSide:"left",
|
||||
/*+*/ bindToButtonByHeight: null,
|
||||
/*+*/ extruderParentElement: null,
|
||||
sensibility:800,
|
||||
position:"top",
|
||||
accordionPanels:true,
|
||||
/*~*/ top:"auto", // =topFlap. For compatibility with the previous version
|
||||
/*+*/ topFlap:"auto",
|
||||
/*+*/ topBlock:0,
|
||||
extruderOpacity:1,
|
||||
zIndex:'max',
|
||||
flapMargin:35,
|
||||
textOrientation:"bt", // or "tb" (top-bottom or bottom-top)
|
||||
onExtOpen:function(){},
|
||||
onExtContentLoad:function(){},
|
||||
onExtClose:function(){},
|
||||
hidePanelsOnClose:true,
|
||||
closeOnClick:true,
|
||||
closeOnExternalClick:true,
|
||||
autoCloseTime:0,
|
||||
autoOpenTime:0,
|
||||
slideTimer:300
|
||||
},
|
||||
|
||||
buildMbExtruder: function(options){
|
||||
return this.each (function (){
|
||||
this.options = {};
|
||||
$.extend (this.options, $.mbExtruder.defaults);
|
||||
$.extend (this.options, options);
|
||||
|
||||
this.idx=document.extruder.idx;
|
||||
document.extruder.idx++;
|
||||
var extruder,extruderContent,wrapper,extruderStyle,wrapperStyle,txt,closeTimer,openTimer;
|
||||
extruder= $(this);
|
||||
extruderContent=extruder.html();
|
||||
/*+*/
|
||||
if (this.options.top) this.options.topFlap = this.options.top;
|
||||
if (this.options.width > window.innerWidth) {
|
||||
this.options.width = window.innerWidth;
|
||||
}
|
||||
/*-*/
|
||||
extruder.css("zIndex",100);
|
||||
var isVertical = this.options.position=="left" || this.options.position=="right";
|
||||
var extW= isVertical?1: this.options.width;
|
||||
/*+*/ if (this.options.selectorResponsiveBlock) {
|
||||
/*+*/ var c= $("<div/>").addClass("extruder-content").css({width:extW, display:"none"});
|
||||
} else {
|
||||
var c= $("<div/>").addClass("extruder-content").css({overflow:"hidden", width:extW, display:"none"});
|
||||
}
|
||||
c.append(extruderContent);
|
||||
extruder.html(c);
|
||||
|
||||
var position=this.options.positionFixed?"fixed":"absolute";
|
||||
extruder.addClass("extruder");
|
||||
extruder.addClass(this.options.position);
|
||||
var isHorizontal = this.options.position=="top" || this.options.position=="bottom";
|
||||
extruderStyle =
|
||||
this.options.position=="top" ?
|
||||
{position:position,top:0,left:"50%",marginLeft:-this.options.width/2,width:this.options.width}:
|
||||
this.options.position=="bottom" ?
|
||||
{position:position,bottom:0,left:"50%",marginLeft:-this.options.width/2,width:this.options.width}:
|
||||
this.options.position=="left" ?
|
||||
{position:position,top:this.options.topBlock,left:0,width:1}:
|
||||
{position:position,top:this.options.topBlock,right:0,width:1};
|
||||
extruder.css(extruderStyle);
|
||||
extruder.css({opacity:this.options.extruderOpacity});
|
||||
extruder.wrapInner("<div class='extruder-wrapper'></div>");
|
||||
wrapper= extruder.find(".extruder-wrapper");
|
||||
|
||||
wrapperStyle={position:"absolute", width:isVertical?1:this.options.width};
|
||||
wrapper.css(wrapperStyle);
|
||||
|
||||
if (isHorizontal){
|
||||
this.options.position=="top"? document.extruder.top++ : document.extruder.bottom++;
|
||||
if (document.extruder.top >1 || document.extruder.bottom>1){
|
||||
alert("more than 1 mb.extruder on top or bottom is not supported jet... hope soon!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($.metadata){
|
||||
$.metadata.setType("class");
|
||||
if (extruder.metadata().title) extruder.attr("extTitle",extruder.metadata().title);
|
||||
if (extruder.metadata().url) extruder.attr("extUrl",extruder.metadata().url);
|
||||
if (extruder.metadata().data) extruder.attr("extData",extruder.metadata().data);
|
||||
}
|
||||
|
||||
var flapFooter=$("<div class='footer'/>");
|
||||
var flap=$("<div class='flap'><span class='flapLabel'/></div>");
|
||||
if (!this.options.noFlap) { /*+*/
|
||||
if (document.extruder.bottom){
|
||||
wrapper.prepend(flapFooter);
|
||||
wrapper.prepend(flap);
|
||||
}else{
|
||||
wrapper.append(flapFooter);
|
||||
wrapper.append(flap);
|
||||
}
|
||||
}
|
||||
txt=extruder.attr("extTitle")?extruder.attr("extTitle"): "";
|
||||
var flapLabel = extruder.find(".flapLabel");
|
||||
flapLabel.text(txt);
|
||||
if(isVertical){
|
||||
flapLabel.html(txt).css({whiteSpace:"noWrap"});
|
||||
var orientation = this.options.textOrientation == "tb";
|
||||
/*+*/ flapLabel.css({transform: "rotate(180deg)", writingMode: "vertical-rl"});
|
||||
}else{
|
||||
flapLabel.html(txt).css({whiteSpace:"noWrap"});
|
||||
}
|
||||
|
||||
if (extruder.attr("extUrl")){
|
||||
extruder.setMbExtruderContent({
|
||||
url:extruder.attr("extUrl"),
|
||||
data:extruder.attr("extData"),
|
||||
callback: function(){
|
||||
if (extruder.get(0).options.onExtContentLoad) extruder.get(0).options.onExtContentLoad();
|
||||
}
|
||||
})
|
||||
}else{
|
||||
/*+*/
|
||||
const width = (this.options.noFlap) ? extruder.get(0).options.width : extruder.get(0).options.width-20;
|
||||
var container=$("<div>").addClass("text").css({width:width, overflowY:"auto"});
|
||||
c.wrapInner(container);
|
||||
extruder.setExtruderVoicesAction();
|
||||
}
|
||||
|
||||
flap.on("click",function(){
|
||||
if (!extruder.attr("isOpened")){
|
||||
extruder.openMbExtruder();
|
||||
}else{
|
||||
extruder.closeMbExtruder();
|
||||
}
|
||||
}).on("mouseenter",function(){
|
||||
if(extruder.get(0).options.autoOpenTime>0){
|
||||
openTimer=setTimeout(function(){
|
||||
extruder.openMbExtruder();
|
||||
$(document).one("click.extruder"+extruder.get(0).idx,function(){extruder.closeMbExtruder();});
|
||||
},extruder.get(0).options.autoOpenTime);
|
||||
}
|
||||
}).on("mouseleave",function(){
|
||||
clearTimeout(openTimer);
|
||||
});
|
||||
c.on("mouseleave", function(e){
|
||||
if(extruder.get(0).options.closeOnExternalClick){
|
||||
|
||||
//Chrome bug: FORMELEMENT fire mouseleave event.
|
||||
if(!$(e.target).parents().is(".text") && !$(e.target).is("select"))
|
||||
$(document).one("click.extruder"+extruder.get(0).idx,function(){extruder.closeMbExtruder();});
|
||||
}
|
||||
closeTimer=setTimeout(function(){
|
||||
|
||||
if(extruder.get(0).options.autoCloseTime > 0){
|
||||
extruder.closeMbExtruder();
|
||||
}
|
||||
},extruder.get(0).options.autoCloseTime);
|
||||
}).on("mouseenter", function(){
|
||||
clearTimeout(closeTimer);
|
||||
$(document).off("click.extruder"+extruder.get(0).idx);
|
||||
});
|
||||
|
||||
if (isVertical){
|
||||
c.css({ height:"100%"});
|
||||
if(this.options.topFlap=="auto") {
|
||||
flap.css({top:100+(this.options.position=="left"?document.extruder.left:document.extruder.right)});
|
||||
//this.options.position=="left"?document.extruder.left+=labelH+this.options.flapMargin:document.extruder.right+= labelH+this.options.flapMargin;
|
||||
}else{
|
||||
flap.css({top:this.options.topFlap});
|
||||
}
|
||||
var clicDiv=$("<div/>").css({position:"absolute",top:0,left:0,width:"100%",height:"100%",background:"transparent"});
|
||||
flap.append(clicDiv);
|
||||
}
|
||||
|
||||
this.originalWidth = this.options.width;
|
||||
|
||||
$(window).on("resize",function(){ // Perhaps this can be removed?
|
||||
extruder.adjustSize();
|
||||
})
|
||||
/*+*/
|
||||
// Tracking menu scrolling
|
||||
if (this.options.bindToButtonByHeight) {
|
||||
document.querySelectorAll('.sidebar-layout, .sidebar-content').forEach(function(el) {
|
||||
el.addEventListener('scroll', function () {
|
||||
extruder.adjustSize();
|
||||
});
|
||||
});
|
||||
// Tracking the resizing (collapse/expand) of the menu
|
||||
const observerLeftSidebar = new window.ResizeObserver(entries => {
|
||||
extruder.adjustSize();
|
||||
})
|
||||
if (this.options.extruderParentElement) {
|
||||
observerLeftSidebar.observe(this.options.extruderParentElement);
|
||||
}
|
||||
}
|
||||
/*-*/
|
||||
});
|
||||
},
|
||||
|
||||
adjustSize:function(){
|
||||
|
||||
var $extruder = this;
|
||||
var extruder = $extruder.get(0);
|
||||
|
||||
var isHorizontal = extruder.options.position=="top" || extruder.options.position=="bottom";
|
||||
|
||||
if(isHorizontal){
|
||||
|
||||
if( $(window).width() < extruder.options.width){
|
||||
$extruder.css({width:$(window).width(), marginLeft:0, left:0});
|
||||
$extruder.find(".extruder-wrapper, .extruder-content, .extruder-container").css({width:"100%"});
|
||||
}else{
|
||||
$extruder.css({width:extruder.options.width, left:"50%",marginLeft:-extruder.options.width/2});
|
||||
$extruder.find(".extruder-wrapper, .extruder-content, .extruder-container").css({width:"100%"});
|
||||
}
|
||||
|
||||
} else{
|
||||
/*+*/
|
||||
if (extruder.options.bindToButtonByHeight) {
|
||||
const anchorElement = $j(extruder.options.bindToButtonByHeight);
|
||||
const extWrapper = extruder.querySelector('.extruder-wrapper');
|
||||
const responsiveBlock = extWrapper.querySelector(extruder.options.selectorResponsiveBlock);
|
||||
const responsiveBlockHeight = (responsiveBlock) ? $(responsiveBlock)[0].clientHeight : 0;
|
||||
let topPointBlock = 0;
|
||||
|
||||
const anchorOffsetTop = anchorElement.offset().top;
|
||||
const bottom = (anchorOffsetTop > 0 ? anchorOffsetTop : 0) + $(extWrapper)[0].clientHeight; // BOTTOM of the extruder block
|
||||
|
||||
if (anchorOffsetTop > 0) { // verything is fine, we move our extruder block up
|
||||
topPointBlock = anchorOffsetTop;
|
||||
}
|
||||
if (bottom > window.innerHeight) { // We've hit bottom
|
||||
topPointBlock = window.innerHeight - responsiveBlockHeight;
|
||||
}
|
||||
if (responsiveBlock) {
|
||||
const deltaH = $(extWrapper)[0].clientHeight - responsiveBlockHeight;
|
||||
if ($(responsiveBlock)[0].scrollHeight > window.innerHeight - deltaH) { // Doesn't fit vertically into the window
|
||||
topPointBlock = 0;
|
||||
responsiveBlock.style.height = window.innerHeight - deltaH +'px';
|
||||
responsiveBlock.style.overflow = 'auto';
|
||||
} else {
|
||||
responsiveBlock.style.height = 'auto';
|
||||
responsiveBlock.style.overflow = 'visible'; // Otherwise, the Select dropdown elements will not extend beyond the block.
|
||||
}
|
||||
}
|
||||
extruder.options.topBlock = topPointBlock;
|
||||
$extruder.css({top:extruder.options.topBlock});
|
||||
}
|
||||
if (extruder.options.attachToParentSide == 'right') {
|
||||
extruder.options.left = (extruder.options.extruderParentElement) ? $j(extruder.options.extruderParentElement)[0].clientWidth : 0;
|
||||
$extruder.css({left:extruder.options.left});
|
||||
}
|
||||
/*-*/
|
||||
if(window.innerWidth-20 < extruder.originalWidth){
|
||||
extruder.options.width = window.innerWidth-20;
|
||||
}else{
|
||||
extruder.options.width = extruder.originalWidth;
|
||||
}
|
||||
|
||||
if($extruder.attr("isOpened")){
|
||||
$extruder.find('.extruder-content').css({width: extruder.options.width});
|
||||
$extruder.find(".extruder-wrapper, .extruder-content, .extruder-container").css({width:extruder.options.width});
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
setMbExtruderContent: function(options){
|
||||
this.options = {
|
||||
url:false,
|
||||
data:"",
|
||||
callback:function(){}
|
||||
};
|
||||
$.extend (this.options, options);
|
||||
if (!this.options.url || this.options.url.length==0){
|
||||
alert("internal error: no URL to call");
|
||||
return;
|
||||
}
|
||||
var url=this.options.url;
|
||||
var data=this.options.data;
|
||||
var where=$(this), voice;
|
||||
var cb= this.options.callback;
|
||||
var container=$("<div>").addClass("extruder-container");
|
||||
container.css({width:$(this).get(0).options.width});
|
||||
where.find(".extruder-content").wrapInner(container);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
data: data,
|
||||
async:true,
|
||||
dataType:"html",
|
||||
success: function(html){
|
||||
where.find(".extruder-container").html(html);
|
||||
voice=where.find(".voice");
|
||||
voice.hover(function(){$(this).addClass("hover");},function(){$(this).removeClass("hover");});
|
||||
where.setExtruderVoicesAction();
|
||||
if (cb) {
|
||||
setTimeout(function(){cb();},100);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
openMbExtruder:function(c){
|
||||
var extruder= $(this);
|
||||
extruder.adjustSize();
|
||||
extruder.attr("isOpened",true);
|
||||
$(document).off("click.extruder"+extruder.get(0).idx);
|
||||
var opt= extruder.get(0).options;
|
||||
extruder.addClass("isOpened");
|
||||
var position = opt.position;
|
||||
extruder.mb_bringToFront(opt.zIndex);
|
||||
if (position=="top" || position=="bottom"){
|
||||
/*+*/ extruder.css("left",opt.left);
|
||||
extruder.find('.extruder-content').slideDown( opt.slideTimer);
|
||||
if(opt.onExtOpen) opt.onExtOpen();
|
||||
}else{
|
||||
/*+*/ extruder.css("top",opt.topBlock);
|
||||
extruder.find('.extruder-wrapper').css({width:""});
|
||||
extruder.find('.extruder-content').css({display:"block"});
|
||||
extruder.find('.extruder-content').animate({ width: opt.width}, opt.slideTimer,function(){
|
||||
// There may be a negative impact, but it hasn't shown up yet...
|
||||
extruder.find(".extruder-container").css({width: opt.width});
|
||||
});
|
||||
if(opt.onExtOpen) opt.onExtOpen();
|
||||
}
|
||||
|
||||
if (c) {
|
||||
setTimeout(function(){
|
||||
$(document).one("click.extruder"+extruder.get(0).idx,function(){extruder.closeMbExtruder();});
|
||||
},100);
|
||||
}
|
||||
if (opt.bindToButtonByHeight) {
|
||||
setTimeout(function(){
|
||||
extruder.adjustSize();
|
||||
},100);
|
||||
}
|
||||
},
|
||||
|
||||
closeMbExtruder:function(){
|
||||
var extruder= $(this);
|
||||
extruder.removeAttr("isOpened");
|
||||
var opt= extruder.get(0).options;
|
||||
if (!opt) return;
|
||||
extruder.removeClass("isOpened");
|
||||
$(document).off("click.extruder"+extruder.get(0).idx);
|
||||
extruder.css("opacity",opt.extruderOpacity);
|
||||
if(opt.hidePanelsOnClose) extruder.hidePanelsOnClose();
|
||||
if (opt.position=="top" || opt.position=="bottom"){
|
||||
extruder.find('.extruder-content').slideUp(opt.slideTimer);
|
||||
if(opt.onExtClose) opt.onExtClose();
|
||||
}else if (opt.position=="left" || opt.position=="right"){
|
||||
extruder.find('.extruder-content').animate({ width: 1 }, opt.slideTimer,function(){
|
||||
// There may be a negative impact, but it hasn't shown up yet...
|
||||
extruder.find('.extruder-wrapper').css({width:1});
|
||||
extruder.find('.extruder-content').css({display:"none"});
|
||||
if(opt.onExtClose) opt.onExtClose();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jQuery.fn.mb_bringToFront = function(zIndex){
|
||||
if (zIndex == 'max') {
|
||||
var zi=10;
|
||||
$('*').each(function() {
|
||||
if($(this).css("position")=="absolute" || $(this).css("position")=="fixed"){
|
||||
const cur = parseInt($(this).css('zIndex'));
|
||||
zi = cur > zi ? cur : zi;
|
||||
}
|
||||
});
|
||||
$(this).css('zIndex',zi+=1);
|
||||
return zi;
|
||||
} else {
|
||||
$(this).css('zIndex',zIndex);
|
||||
return zIndex;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* EXTRUDER CONTENT
|
||||
*/
|
||||
|
||||
$.fn.setExtruderVoicesAction=function(){
|
||||
var extruder=$(this);
|
||||
var opt=extruder.get(0).options;
|
||||
var voices= $(this).find(".voice");
|
||||
voices.each(function(){
|
||||
var voice=$(this);
|
||||
if ($.metadata){
|
||||
$.metadata.setType("class");
|
||||
if (voice.metadata().panel) voice.attr("panel",voice.metadata().panel);
|
||||
if (voice.metadata().data) voice.attr("data",voice.metadata().data);
|
||||
if (voice.metadata().disabled) voice.attr("setDisabled", voice.metadata().disabled);
|
||||
}
|
||||
|
||||
if (voice.attr("setDisabled"))
|
||||
voice.disableExtruderVoice();
|
||||
|
||||
if (voice.attr("panel") && voice.attr("panel")!="false"){
|
||||
voice.append("<span class='settingsBtn'/>");
|
||||
voice.find(".settingsBtn").css({opacity:.5});
|
||||
voice.find(".settingsBtn").hover(
|
||||
function(){
|
||||
$(this).css({opacity:1});
|
||||
},
|
||||
function(){
|
||||
$(this).not(".sel").css({opacity:.5});
|
||||
}).click(function(){
|
||||
if ($(this).parents().hasClass("sel")){
|
||||
if(opt.accordionPanels)
|
||||
extruder.hidePanelsOnClose();
|
||||
else
|
||||
$(this).closePanel();
|
||||
return;
|
||||
}
|
||||
|
||||
if(opt.accordionPanels){
|
||||
extruder.find(".optionsPanel").slideUp(400,function(){$(this).remove();});
|
||||
voices.removeClass("sel");
|
||||
voices.find(".settingsBtn").removeClass("sel").css({opacity:.5});
|
||||
}
|
||||
var content=$("<div class='optionsPanel'></div>");
|
||||
voice.after(content);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: voice.attr("panel"),
|
||||
data: voice.attr("data"),
|
||||
async:true,
|
||||
dataType:"html",
|
||||
success: function(html){
|
||||
var c= $(html);
|
||||
content.html(c);
|
||||
content.children().not(".text")
|
||||
.addClass("panelVoice")
|
||||
.click(function(){
|
||||
if(opt.closeOnClick)
|
||||
extruder.closeMbExtruder();
|
||||
});
|
||||
content.slideDown(400);
|
||||
}
|
||||
});
|
||||
voice.addClass("sel");
|
||||
voice.find(".settingsBtn").addClass("sel").css({opacity:1});
|
||||
});
|
||||
}
|
||||
|
||||
if (voice.find("a").length==0 && voice.attr("panel")){
|
||||
voice.find(".label").not(".disabled").css("cursor","pointer").click(function(){
|
||||
voice.find(".settingsBtn").click();
|
||||
});
|
||||
}
|
||||
|
||||
if ((!voice.attr("panel") || voice.attr("panel")=="false" ) && (!voice.attr("setDisabled") || voice.attr("setDisabled")!="true")){
|
||||
voice.find(".label").click(function(){
|
||||
extruder.hidePanelsOnClose();
|
||||
if(opt.closeOnClick)
|
||||
extruder.closeMbExtruder();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.disableExtruderVoice=function(){
|
||||
var voice=$(this);
|
||||
var label = voice.find(".label");
|
||||
voice.removeClass("sel");
|
||||
voice.next(".optionsPanel").slideUp(400,function(){$(this).remove();});
|
||||
voice.attr("setDisabled",true);
|
||||
label.css("opacity",.4);
|
||||
voice.hover(function(){$(this).removeClass("hover");},function(){$(this).removeClass("hover");});
|
||||
label.addClass("disabled").css("cursor","default");
|
||||
voice.find(".settingsBtn").hide();
|
||||
voice.on("click",function(event){
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.enableExtruderVoice=function(){
|
||||
var voice=$(this);
|
||||
voice.attr("setDisabled",false);
|
||||
voice.find(".label").css("opacity",1);
|
||||
voice.find(".label").removeClass("disabled").css("cursor","pointer");
|
||||
voice.off("click");
|
||||
voice.find(".settingsBtn").show();
|
||||
};
|
||||
|
||||
$.fn.hidePanelsOnClose=function(){
|
||||
var voices= $(this).find(".voice");
|
||||
$(this).find(".optionsPanel").slideUp(400,function(){$(this).remove();});
|
||||
voices.removeClass("sel");
|
||||
voices.find(".settingsBtn").removeClass("sel").css("opacity",.5);
|
||||
};
|
||||
|
||||
$.fn.openPanel=function(){
|
||||
var voice=$(this).hasClass("voice") ? $(this) : $(this).find(".voice");
|
||||
voice.each(function(){
|
||||
if($(this).hasClass("sel")) return;
|
||||
$(this).find(".settingsBtn").click();
|
||||
})
|
||||
};
|
||||
|
||||
$.fn.closePanel=function(){
|
||||
var voice=$(this).hasClass("voice") ? $(this) : $(this).parent(".voice");
|
||||
voice.next(".optionsPanel").slideUp(400,function(){$(this).remove();});
|
||||
voice.removeClass("sel");
|
||||
$(this).removeClass("sel").css("opacity",.5);
|
||||
};
|
||||
|
||||
$.fn.buildMbExtruder=$.mbExtruder.buildMbExtruder;
|
||||
$.fn.setMbExtruderContent=$.mbExtruder.setMbExtruderContent;
|
||||
$.fn.closeMbExtruder=$.mbExtruder.closeMbExtruder;
|
||||
$.fn.openMbExtruder=$.mbExtruder.openMbExtruder;
|
||||
$.fn.adjustSize=$.mbExtruder.adjustSize;
|
||||
|
||||
})(jQuery);
|
||||
21
web/skins/classic/assets/pro-sidebar-template/LICENSE
Normal file
21
web/skins/classic/assets/pro-sidebar-template/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Mohamed AZOUAOUI
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
246
web/skins/classic/assets/pro-sidebar-template/README.md
Normal file
246
web/skins/classic/assets/pro-sidebar-template/README.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# Pro sidebar template
|
||||
|
||||
Responsive layout with advanced sidebar menu built with SCSS and vanilla Javascript
|
||||
|
||||
## Demo
|
||||
|
||||
[See it live](https://azouaoui-med.github.io/pro-sidebar-template)
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
# clone the repo
|
||||
$ git clone https://github.com/azouaoui-med/pro-sidebar-template.git my-project
|
||||
|
||||
# go into app's directory
|
||||
$ cd my-project
|
||||
|
||||
# install app's dependencies
|
||||
$ yarn install
|
||||
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
# serve with hot reload at localhost:8080
|
||||
$ yarn start
|
||||
|
||||
# build app for production
|
||||
$ yarn build
|
||||
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### Layout
|
||||
|
||||
The layout for this template is based on [css pro layout](https://github.com/azouaoui-med/css-pro-layout) package, please refer to the [docs](https://azouaoui-med.github.io/css-pro-layout/) for more information
|
||||
|
||||
### Sidebar
|
||||
|
||||
Responsive navigation element for building vertical menu items
|
||||
|
||||
**Sidebar Image**
|
||||
|
||||
Adding background image requires adding `.has-bg-image` class to sidebar component, and the image needs to be inside `.image-wrapper` component
|
||||
|
||||
```html
|
||||
<aside id="sidebar" class="sidebar break-point-lg has-bg-image">
|
||||
<div class="image-wrapper">
|
||||
<img src="assets/images/sidebar-bg.jpg" alt="sidebar background" />
|
||||
</div>
|
||||
<div class="sidebar-layout">
|
||||
<!-- Content here -->
|
||||
</div>
|
||||
</aside>
|
||||
```
|
||||
|
||||
### Sidebar Layout
|
||||
|
||||
Sidebar comes with layout support for better organization of the inner structure
|
||||
|
||||
```html
|
||||
<aside id="sidebar" class="sidebar break-point-lg">
|
||||
<div class="sidebar-layout">
|
||||
<div class="sidebar-header">
|
||||
<!-- Header content here -->
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<!-- Content here -->
|
||||
</div>
|
||||
<div class="sidebar-footer">
|
||||
<!-- Footer content here -->
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
```
|
||||
|
||||
More on the sidebar [here](https://azouaoui-med.github.io/css-pro-layout/docs/reference/sidebar)
|
||||
|
||||
### Menu
|
||||
|
||||
Wrapper component that groups all menu items
|
||||
|
||||
```html
|
||||
<nav class="menu">
|
||||
<!-- Content here -->
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Open current submenu**
|
||||
|
||||
Use `.open-current-submenu` to enable opening only one submenu component at a time
|
||||
|
||||
```html
|
||||
<nav class="menu open-current-submenu">
|
||||
<!-- Content here -->
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Icon shape**
|
||||
|
||||
A set of classes are provided to restyle menu icons
|
||||
|
||||
- `.icon-shape-square`
|
||||
- `.icon-shape-rounded`
|
||||
- `.icon-shape-circle`
|
||||
|
||||
```html
|
||||
<nav class="menu icon-shape-circle">
|
||||
<!-- Content here -->
|
||||
</nav>
|
||||
```
|
||||
|
||||
### Menu Item
|
||||
|
||||
Building menu item requires having `.menu-item` class in the wrapper and `.menu-title` for the text
|
||||
|
||||
```html
|
||||
<nav class="menu">
|
||||
<ul>
|
||||
<li class="menu-item">
|
||||
<a href="#">
|
||||
<span class="menu-title">menu text</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- More menu items -->
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Menu Icon**
|
||||
|
||||
Use `.menu-icon` to add an icon to menu items
|
||||
|
||||
```html
|
||||
<nav class="menu">
|
||||
<ul>
|
||||
<li class="menu-item">
|
||||
<a href="#">
|
||||
<span class="menu-icon">
|
||||
<i class="ri-service-fill"></i>
|
||||
</span>
|
||||
<span class="menu-title">menu text</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- More menu items -->
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Prefix & Suffix**
|
||||
|
||||
Menu item also supports having prefix and suffix components
|
||||
|
||||
```html
|
||||
<nav class="menu">
|
||||
<ul>
|
||||
<li class="menu-item">
|
||||
<a href="#">
|
||||
<span class="menu-icon">
|
||||
<i class="ri-service-fill"></i>
|
||||
</span>
|
||||
<span class="menu-prefix">prefix</span>
|
||||
<span class="menu-title">menu text</span>
|
||||
<span class="menu-suffix">suffix</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- More menu items -->
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
### Sub Menu
|
||||
|
||||
Add `.sub-menu` class to menu item and create a wrapper component with `sub-menu-list` class to group sub menu items
|
||||
|
||||
> Its possible to have unlimited nesting menu items
|
||||
|
||||
```html
|
||||
<nav class="menu">
|
||||
<ul>
|
||||
<li class="menu-item sub-menu">
|
||||
<a href="#">
|
||||
<span class="menu-title">menu text</span>
|
||||
</a>
|
||||
<div class="sub-menu-list">
|
||||
<li class="menu-item">
|
||||
<a href="#">
|
||||
<span class="menu-title">sub menu text</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- More sub menu items -->
|
||||
</div>
|
||||
</li>
|
||||
<!-- More menu items -->
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Open default**
|
||||
|
||||
Use `.open` class to have sub menu expanded by default
|
||||
|
||||
```html
|
||||
<nav class="menu">
|
||||
<ul>
|
||||
<li class="menu-item sub-menu open">
|
||||
<a href="#">
|
||||
<span class="menu-title">menu text</span>
|
||||
</a>
|
||||
<div class="sub-menu-list">
|
||||
<li class="menu-item">
|
||||
<a href="#">
|
||||
<span class="menu-title">sub menu text</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- More sub menu items -->
|
||||
</div>
|
||||
</li>
|
||||
<!-- More menu items -->
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
### Customization
|
||||
|
||||
Update SCSS variables in `src/styles/_variables.scss` to customize the template
|
||||
|
||||
```scss
|
||||
$text-color: #b3b8d4;
|
||||
$secondary-text-color: #dee2ec;
|
||||
$bg-color: #0c1e35;
|
||||
$secondary-bg-color: #0b1a2c;
|
||||
$border-color: rgba(#535d7d, 0.3);
|
||||
$sidebar-header-height: 64px;
|
||||
$sidebar-footer-height: 64px;
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This code is released under the [MIT](https://github.com/azouaoui-med/pro-sidebar-template/blob/gh-pages/LICENSE) license.
|
||||
@@ -0,0 +1,6 @@
|
||||
Source: https://github.com/azouaoui-med/pro-sidebar-template
|
||||
Since the source has not changed since the beginning of 2023, IgorA100 decided to make small local changes to the code.
|
||||
Make all changes ONLY to files in the ./src folder
|
||||
Then build with the ./build.sh command
|
||||
The ./dist folder will contain the minimized files for PRODUCT mode
|
||||
The ./dist_dev folder will contain the files for DEVELOP mode
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
5
web/skins/classic/assets/pro-sidebar-template/build.sh
Normal file
5
web/skins/classic/assets/pro-sidebar-template/build.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
yarn install
|
||||
yarn build
|
||||
yarn build:dev
|
||||
4
web/skins/classic/assets/pro-sidebar-template/dist/main.css
vendored
Normal file
4
web/skins/classic/assets/pro-sidebar-template/dist/main.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/skins/classic/assets/pro-sidebar-template/dist/main.css.map
vendored
Normal file
1
web/skins/classic/assets/pro-sidebar-template/dist/main.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
web/skins/classic/assets/pro-sidebar-template/dist/main.js
vendored
Normal file
2
web/skins/classic/assets/pro-sidebar-template/dist/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/skins/classic/assets/pro-sidebar-template/dist/main.js.map
vendored
Normal file
1
web/skins/classic/assets/pro-sidebar-template/dist/main.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
763
web/skins/classic/assets/pro-sidebar-template/dist_dev/main.css
Normal file
763
web/skins/classic/assets/pro-sidebar-template/dist_dev/main.css
Normal file
@@ -0,0 +1,763 @@
|
||||
@import url(https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap);
|
||||
/*@import 'css-pro-layout/dist/scss/css-pro-layout.scss';*/
|
||||
.layout-main {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.layout-main.has-sidebar {
|
||||
flex-direction: row;
|
||||
}
|
||||
.layout-main .header {
|
||||
transition: width, 0.3s;
|
||||
height: 64px;
|
||||
min-height: 64px;
|
||||
position: relative;
|
||||
}
|
||||
.layout-main .sidebar-main {
|
||||
width: 250px;
|
||||
min-width: 250px;
|
||||
transition: width, left, right, 0.3s;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed {
|
||||
width: 80px;
|
||||
min-width: 80px;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.layout-main .sidebar-main.break-point-xs {
|
||||
position: fixed;
|
||||
left: -250px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xs.collapsed {
|
||||
left: -80px;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xs.toggled {
|
||||
left: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xs.toggled ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xs ~ .layout-main .header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.layout-main .sidebar-main.break-point-sm {
|
||||
position: fixed;
|
||||
left: -250px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-sm.collapsed {
|
||||
left: -80px;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-sm.toggled {
|
||||
left: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-sm.toggled ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-sm ~ .layout-main .header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.layout-main .sidebar-main.break-point-md {
|
||||
position: fixed;
|
||||
left: -250px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-md.collapsed {
|
||||
left: -80px;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-md.toggled {
|
||||
left: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-md.toggled ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-md ~ .layout-main .header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.layout-main .sidebar-main.break-point-lg {
|
||||
position: fixed;
|
||||
left: -250px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-lg.collapsed {
|
||||
left: -80px;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-lg.toggled {
|
||||
left: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-lg.toggled ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-lg ~ .layout-main .header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.layout-main .sidebar-main.break-point-xl {
|
||||
position: fixed;
|
||||
left: -250px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xl.collapsed {
|
||||
left: -80px;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xl.toggled {
|
||||
left: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xl.toggled ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xl ~ .layout-main .header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1600px) {
|
||||
.layout-main .sidebar-main.break-point-xxl {
|
||||
position: fixed;
|
||||
left: -250px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xxl.collapsed {
|
||||
left: -80px;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xxl.toggled {
|
||||
left: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xxl.toggled ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
.layout-main .sidebar-main.break-point-xxl ~ .layout-main .header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
.layout-main .footer {
|
||||
height: 64px;
|
||||
min-height: 64px;
|
||||
}
|
||||
.layout-main .content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.layout-main .overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
z-index: 99;
|
||||
display: none;
|
||||
}
|
||||
.layout-main .sidebar-toggler {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.layout-main .sidebar-toggler.break-point-xs {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.layout-main .sidebar-toggler.break-point-sm {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.layout-main .sidebar-toggler.break-point-md {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.layout-main .sidebar-toggler.break-point-lg {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.layout-main .sidebar-toggler.break-point-xl {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1600px) {
|
||||
.layout-main .sidebar-toggler.break-point-xxl {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
.layout-main.fixed-sidebar {
|
||||
height: 100%;
|
||||
}
|
||||
.layout-main.fixed-sidebar .sidebar {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.layout-main.fixed-sidebar .sidebar ~ .layout-main {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.layout-main.fixed-header .header {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
.layout-main.fixed-header .header ~ .layout-main,
|
||||
.layout-main.fixed-header .header ~ .content {
|
||||
margin-top: 64px;
|
||||
}
|
||||
.layout-main.fixed-header.fixed-sidebar .header {
|
||||
width: calc(100% - 250px);
|
||||
}
|
||||
.layout-main.fixed-header.fixed-sidebar .sidebar.collapsed ~ .layout-main .header {
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
.layout-main.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.layout-main.rtl .sidebar.break-point-xs {
|
||||
left: auto;
|
||||
right: -250px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-xs.collapsed {
|
||||
left: auto;
|
||||
right: -80px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-xs.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.layout-main.rtl .sidebar.break-point-sm {
|
||||
left: auto;
|
||||
right: -250px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-sm.collapsed {
|
||||
left: auto;
|
||||
right: -80px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-sm.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.layout-main.rtl .sidebar.break-point-md {
|
||||
left: auto;
|
||||
right: -250px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-md.collapsed {
|
||||
left: auto;
|
||||
right: -80px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-md.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.layout-main.rtl .sidebar.break-point-lg {
|
||||
left: auto;
|
||||
right: -250px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-lg.collapsed {
|
||||
left: auto;
|
||||
right: -80px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-lg.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.layout-main.rtl .sidebar.break-point-xl {
|
||||
left: auto;
|
||||
right: -250px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-xl.collapsed {
|
||||
left: auto;
|
||||
right: -80px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-xl.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1600px) {
|
||||
.layout-main.rtl .sidebar.break-point-xxl {
|
||||
left: auto;
|
||||
right: -250px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-xxl.collapsed {
|
||||
left: auto;
|
||||
right: -80px;
|
||||
}
|
||||
.layout-main.rtl .sidebar.break-point-xxl.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*@import '../../public//assets//remixicon/remixicon.css';*/
|
||||
/*
|
||||
.layout {
|
||||
z-index: 1;
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.content {
|
||||
padding: 12px 50px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: auto;
|
||||
margin-bottom: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
*/
|
||||
.sidebar-main {
|
||||
color: #44b8eb;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
.sidebar-main .image-wrapper {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
}
|
||||
.sidebar-main .image-wrapper > img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
.sidebar-main.has-bg-image .sidebar-layout {
|
||||
background-color: rgba(12, 30, 53, 0.85);
|
||||
}
|
||||
.sidebar-main.has-bg-image .image-wrapper {
|
||||
display: block;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.sidebar-main .sidebar-layout {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
background-color: #0c1e35;
|
||||
z-index: 2;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.sidebar-main .sidebar-layout::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
}
|
||||
.sidebar-main .sidebar-layout:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgb(26.1230769231, 65.3076923077, 115.3769230769);
|
||||
}
|
||||
.sidebar-main .sidebar-layout::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
background-color: #0c1e35;
|
||||
}
|
||||
.sidebar-main .sidebar-layout .sidebar-header {
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 22px;
|
||||
}
|
||||
.sidebar-main .sidebar-layout .sidebar-header > span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.sidebar-main .sidebar-layout .sidebar-content {
|
||||
flex-grow: 1;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.sidebar-main .sidebar-layout .sidebar-footer {
|
||||
height: 230px;
|
||||
min-height: 230px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.sidebar-main .sidebar-layout .sidebar-footer > span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@keyframes swing {
|
||||
0%, 30%, 50%, 70%, 100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
10% {
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
40% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
60% {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
80% {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-header {
|
||||
font-weight: 600;
|
||||
padding: 10px 25px;
|
||||
font-size: 0.8em;
|
||||
letter-spacing: 2px;
|
||||
transition: opacity 0.3s;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 38px;
|
||||
padding: 0 20px;
|
||||
color: #44b8eb;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a .menu-icon {
|
||||
font-size: 1.2rem;
|
||||
width: 35px;
|
||||
min-width: 35px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
border-radius: 2px;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a .menu-title {
|
||||
font-size: 0.9em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex-grow: 1;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a .menu-prefix,
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a .menu-suffix {
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a:hover .menu-title {
|
||||
color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a:hover .menu-icon {
|
||||
color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a:hover .menu-icon i {
|
||||
animation: swing ease-in-out 0.5s 1 alternate;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a:hover::after {
|
||||
border-color: #dee2ec !important;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.sub-menu {
|
||||
position: relative;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.sub-menu > a::after {
|
||||
content: "";
|
||||
transition: transform 0.3s;
|
||||
border-right: 2px solid currentcolor;
|
||||
border-bottom: 2px solid currentcolor;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.sub-menu > .sub-menu-list {
|
||||
padding-left: 20px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
z-index: 999;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.sub-menu.open > a {
|
||||
color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.sub-menu.open > a::after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.active > a .menu-title {
|
||||
color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.active > a::after {
|
||||
border-color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item.active > a .menu-icon {
|
||||
color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu > ul > .sub-menu > .sub-menu-list {
|
||||
background-color: #0b1a2c;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu.icon-shape-circle .menu-item a .menu-icon, .layout-main .sidebar-main .sidebar-main-menu.icon-shape-rounded .menu-item a .menu-icon, .layout-main .sidebar-main .sidebar-main-menu.icon-shape-square .menu-item a .menu-icon {
|
||||
background-color: #0b1a2c;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu.icon-shape-circle .menu-item a .menu-icon {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu.icon-shape-rounded .menu-item a .menu-icon {
|
||||
border-radius: 4px;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-main-menu.icon-shape-square .menu-item a .menu-icon {
|
||||
border-radius: 0;
|
||||
}
|
||||
.layout-main .sidebar-main:not(.collapsed) .sidebar-main-menu > ul > .menu-item.sub-menu > .sub-menu-list {
|
||||
visibility: visible !important;
|
||||
position: static !important;
|
||||
transform: translate(0, 0) !important;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-header {
|
||||
opacity: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item > a .menu-prefix,
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item > a .menu-suffix {
|
||||
opacity: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item.sub-menu > a::after {
|
||||
content: "";
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: currentcolor;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
border: none;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item.sub-menu > a:hover::after {
|
||||
background-color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item.sub-menu > .sub-menu-list {
|
||||
transition: none !important;
|
||||
width: 200px;
|
||||
margin-left: 3px !important;
|
||||
border-radius: 4px;
|
||||
display: block !important;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item.active > a::after {
|
||||
background-color: #dee2ec;
|
||||
}
|
||||
.layout-main .sidebar-main.has-bg-image .sidebar-main-menu.icon-shape-circle .menu-item a .menu-icon, .layout-main .sidebar-main.has-bg-image .sidebar-main-menu.icon-shape-rounded .menu-item a .menu-icon, .layout-main .sidebar-main.has-bg-image .sidebar-main-menu.icon-shape-square .menu-item a .menu-icon {
|
||||
background-color: rgba(11, 26, 44, 0.6);
|
||||
}
|
||||
.layout-main .sidebar-main.has-bg-image:not(.collapsed) .sidebar-main-menu > ul > .sub-menu > .sub-menu-list {
|
||||
background-color: rgba(11, 26, 44, 0.6);
|
||||
}
|
||||
.layout-main.rtl .sidebar-main .sidebar-main-menu .menu-item a .menu-icon {
|
||||
margin-left: 10px;
|
||||
margin-right: 0;
|
||||
}
|
||||
.layout-main.rtl .sidebar-main .sidebar-main-menu .menu-item.sub-menu > a::after {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
.layout-main.rtl .sidebar-main .sidebar-main-menu .menu-item.sub-menu > .sub-menu-list {
|
||||
padding-left: 0;
|
||||
padding-right: 20px;
|
||||
}
|
||||
.layout-main.rtl .sidebar-main .sidebar-main-menu .menu-item.sub-menu.open > a::after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.layout-main.rtl .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item.sub-menu a::after {
|
||||
right: auto;
|
||||
left: 10px;
|
||||
}
|
||||
.layout-main.rtl .sidebar-main.collapsed .sidebar-main-menu > ul > .menu-item.sub-menu > .sub-menu-list {
|
||||
margin-left: -3px !important;
|
||||
}
|
||||
|
||||
/*
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
color: #3f4750;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
*/
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
#btn-collapse {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.layout-main .sidebar-main .pro-sidebar-logo {
|
||||
color: #ffa801;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.layout-main .sidebar-main .pro-sidebar-logo > div {
|
||||
width: 45px;
|
||||
min-width: 45px;
|
||||
height: 25px;
|
||||
min-height: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
background-color: #ffa801;
|
||||
margin-right: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
.layout-main .sidebar-main .pro-sidebar-logo > h5 {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 22px;
|
||||
line-height: 25px;
|
||||
transition: opacity 0.3s;
|
||||
opacity: 1;
|
||||
margin: 0 17px;
|
||||
}
|
||||
.layout-main .sidebar-main .footer-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
/* font-size: 0.8em; */
|
||||
padding: 20px 0;
|
||||
border-radius: 8px;
|
||||
width: 180px;
|
||||
min-width: 190px;
|
||||
margin: 0 auto;
|
||||
background-color: #162d4a;
|
||||
}
|
||||
.layout-main .sidebar-main .footer-box img.react-logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.layout-main .sidebar-main .footer-box a {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.layout-main .sidebar-main .sidebar-collapser {
|
||||
transition: left, right, 0.3s;
|
||||
position: fixed;
|
||||
left: calc(250px - 20px);
|
||||
top: 40px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background-color: #00829f;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2em;
|
||||
transform: translateX(50%);
|
||||
z-index: 111;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
box-shadow: 1px 1px 4px #0c1e35;
|
||||
}
|
||||
.layout-main .sidebar-main.has-bg-image .footer-box {
|
||||
/* background-color: rgba(#162d4a, 0.7); */
|
||||
background-color: #34495e;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .pro-sidebar-logo > h5 {
|
||||
opacity: 0;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .footer-box {
|
||||
display: none;
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-collapser {
|
||||
left: calc(80px - 20px);
|
||||
}
|
||||
.layout-main .sidebar-main.collapsed .sidebar-collapser i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.25em 0.4em;
|
||||
font-size: 75%;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: 0.25rem;
|
||||
color: #fff;
|
||||
background-color: #6c757d;
|
||||
}
|
||||
.badge.primary {
|
||||
background-color: #ab2dff;
|
||||
}
|
||||
.badge.secondary {
|
||||
background-color: #079b0b;
|
||||
}
|
||||
|
||||
.sidebar-toggler {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.social-links a {
|
||||
margin: 0 10px;
|
||||
color: #3f4750;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=main.css.map*/
|
||||
File diff suppressed because one or more lines are too long
3276
web/skins/classic/assets/pro-sidebar-template/dist_dev/main.js
Normal file
3276
web/skins/classic/assets/pro-sidebar-template/dist_dev/main.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
plugins: ['postcss-preset-env'],
|
||||
};
|
||||
99
web/skins/classic/assets/pro-sidebar-template/src/index.js
Normal file
99
web/skins/classic/assets/pro-sidebar-template/src/index.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import './styles/styles.scss';
|
||||
import { slideToggle, slideUp, slideDown } from './libs/slide';
|
||||
import {
|
||||
ANIMATION_DURATION,
|
||||
FIRST_SUB_MENUS_BTN,
|
||||
INNER_SUB_MENUS_BTN,
|
||||
SIDEBAR_EL,
|
||||
} from './libs/constants';
|
||||
import Poppers from './libs/poppers';
|
||||
|
||||
const PoppersInstance = new Poppers();
|
||||
|
||||
/**
|
||||
* wait for the current animation to finish and update poppers position
|
||||
*/
|
||||
const updatePoppersTimeout = () => {
|
||||
setTimeout(() => {
|
||||
PoppersInstance.updatePoppers();
|
||||
}, ANIMATION_DURATION);
|
||||
};
|
||||
|
||||
/**
|
||||
* sidebar collapse handler
|
||||
*/
|
||||
const btnCollapse = document.getElementById('btn-collapse');
|
||||
if (btnCollapse) {
|
||||
btnCollapse.addEventListener('click', () => {
|
||||
SIDEBAR_EL.classList.toggle('collapsed');
|
||||
PoppersInstance.closePoppers();
|
||||
if (SIDEBAR_EL.classList.contains('collapsed'))
|
||||
FIRST_SUB_MENUS_BTN.forEach((element) => {
|
||||
element.parentElement.classList.remove('open');
|
||||
});
|
||||
|
||||
updatePoppersTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* sidebar toggle handler (on break point )
|
||||
*/
|
||||
const btnToggle = document.getElementById('btn-toggle');
|
||||
if (btnToggle) {
|
||||
btnToggle.addEventListener('click', () => {
|
||||
SIDEBAR_EL.classList.toggle('toggled');
|
||||
|
||||
updatePoppersTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* toggle sidebar on overlay click
|
||||
*/
|
||||
const btnOverlay = document.getElementById('overlay');
|
||||
if (btnOverlay) {
|
||||
btnOverlay.addEventListener('click', () => {
|
||||
SIDEBAR_EL.classList.toggle('toggled');
|
||||
});
|
||||
}
|
||||
|
||||
const defaultOpenMenus = document.querySelectorAll('.menu-item.sub-menu.open');
|
||||
|
||||
defaultOpenMenus.forEach((element) => {
|
||||
element.lastElementChild.style.display = 'block';
|
||||
});
|
||||
|
||||
/**
|
||||
* handle top level submenu click
|
||||
*/
|
||||
FIRST_SUB_MENUS_BTN.forEach((element) => {
|
||||
element.addEventListener('click', () => {
|
||||
if (SIDEBAR_EL.classList.contains('collapsed'))
|
||||
PoppersInstance.togglePopper(element.nextElementSibling);
|
||||
else {
|
||||
/**
|
||||
* if menu has "open-current-only" class then only one submenu opens at a time
|
||||
*/
|
||||
const parentMenu = element.closest('.menuLeft.open-current-submenu');
|
||||
if (parentMenu)
|
||||
parentMenu
|
||||
.querySelectorAll(':scope > ul > .menu-item.sub-menu > a')
|
||||
.forEach(
|
||||
(el) =>
|
||||
window.getComputedStyle(el.nextElementSibling).display !==
|
||||
'none' && slideUp(el.nextElementSibling)
|
||||
);
|
||||
slideToggle(element.nextElementSibling);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* handle inner submenu click
|
||||
*/
|
||||
INNER_SUB_MENUS_BTN.forEach((element) => {
|
||||
element.addEventListener('click', () => {
|
||||
slideToggle(element.nextElementSibling);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
export const ANIMATION_DURATION = 300;
|
||||
|
||||
export const SIDEBAR_EL = document.getElementById('sidebarMain');
|
||||
|
||||
export const SUB_MENU_ELS = document.querySelectorAll(
|
||||
'.sidebar-main-menu > ul > .menu-item.sub-menu'
|
||||
);
|
||||
|
||||
export const FIRST_SUB_MENUS_BTN = document.querySelectorAll(
|
||||
'.sidebar-main-menu > ul > .menu-item.sub-menu > a'
|
||||
);
|
||||
|
||||
export const INNER_SUB_MENUS_BTN = document.querySelectorAll(
|
||||
'.sidebar-main-menu > ul > .menu-item.sub-menu .menu-item.sub-menu > a'
|
||||
);
|
||||
@@ -0,0 +1,65 @@
|
||||
import { createPopper } from '@popperjs/core';
|
||||
import { SIDEBAR_EL } from './constants';
|
||||
|
||||
class Popper {
|
||||
instance = null;
|
||||
reference = null;
|
||||
popperTarget = null;
|
||||
|
||||
constructor(reference, popperTarget) {
|
||||
this.init(reference, popperTarget);
|
||||
}
|
||||
|
||||
init(reference, popperTarget) {
|
||||
this.reference = reference;
|
||||
this.popperTarget = popperTarget;
|
||||
this.instance = createPopper(this.reference, this.popperTarget, {
|
||||
placement: 'right',
|
||||
strategy: 'fixed',
|
||||
resize: true,
|
||||
modifiers: [
|
||||
{
|
||||
name: 'computeStyles',
|
||||
options: {
|
||||
adaptive: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'flip',
|
||||
options: {
|
||||
fallbackPlacements: ['left', 'right'],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
document.addEventListener(
|
||||
'click',
|
||||
(e) => this.clicker(e, this.popperTarget, this.reference),
|
||||
false,
|
||||
);
|
||||
|
||||
const ro = new ResizeObserver(() => {
|
||||
this.instance.update();
|
||||
});
|
||||
|
||||
ro.observe(this.popperTarget);
|
||||
ro.observe(this.reference);
|
||||
}
|
||||
|
||||
clicker(event, popperTarget, reference) {
|
||||
if (
|
||||
SIDEBAR_EL.classList.contains('collapsed') &&
|
||||
!popperTarget.contains(event.target) &&
|
||||
!reference.contains(event.target)
|
||||
) {
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.instance.state.elements.popper.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
export default Popper;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { SUB_MENU_ELS } from './constants';
|
||||
import Popper from './popper';
|
||||
|
||||
class Poppers {
|
||||
subMenuPoppers = [];
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
SUB_MENU_ELS.forEach((element) => {
|
||||
this.subMenuPoppers.push(new Popper(element, element.lastElementChild));
|
||||
this.closePoppers();
|
||||
});
|
||||
}
|
||||
|
||||
togglePopper(target) {
|
||||
if (window.getComputedStyle(target).visibility === 'hidden') {
|
||||
target.style.visibility = 'visible';
|
||||
target.style.height = '100%';
|
||||
} else {
|
||||
target.style.visibility = 'hidden';
|
||||
target.style.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
updatePoppers() {
|
||||
this.subMenuPoppers.forEach((element) => {
|
||||
if (!element.instance.state.elements.popper.parentElement.classList.contains('open')) {
|
||||
element.instance.state.elements.popper.style.display = 'none';
|
||||
}
|
||||
element.instance.update();
|
||||
});
|
||||
}
|
||||
|
||||
closePoppers() {
|
||||
this.subMenuPoppers.forEach((element) => {
|
||||
element.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Poppers;
|
||||
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable no-unused-expressions */
|
||||
import { ANIMATION_DURATION } from './constants';
|
||||
|
||||
export const slideUp = (target, duration = ANIMATION_DURATION) => {
|
||||
const { parentElement } = target;
|
||||
parentElement.classList.remove('open');
|
||||
target.style.transitionProperty = 'height, margin, padding';
|
||||
target.style.transitionDuration = `${duration}ms`;
|
||||
target.style.boxSizing = 'border-box';
|
||||
target.style.height = `${target.offsetHeight}px`;
|
||||
target.offsetHeight;
|
||||
target.style.overflow = 'hidden';
|
||||
target.style.height = 0;
|
||||
target.style.paddingTop = 0;
|
||||
target.style.paddingBottom = 0;
|
||||
target.style.marginTop = 0;
|
||||
target.style.marginBottom = 0;
|
||||
window.setTimeout(() => {
|
||||
target.style.display = 'none';
|
||||
target.style.removeProperty('height');
|
||||
target.style.removeProperty('padding-top');
|
||||
target.style.removeProperty('padding-bottom');
|
||||
target.style.removeProperty('margin-top');
|
||||
target.style.removeProperty('margin-bottom');
|
||||
target.style.removeProperty('overflow');
|
||||
target.style.removeProperty('transition-duration');
|
||||
target.style.removeProperty('transition-property');
|
||||
}, duration);
|
||||
};
|
||||
|
||||
export const slideDown = (target, duration = ANIMATION_DURATION) => {
|
||||
const { parentElement } = target;
|
||||
parentElement.classList.add('open');
|
||||
target.style.removeProperty('display');
|
||||
let { display } = window.getComputedStyle(target);
|
||||
if (display === 'none') display = 'block';
|
||||
target.style.display = display;
|
||||
const height = target.offsetHeight;
|
||||
target.style.overflow = 'hidden';
|
||||
target.style.height = 0;
|
||||
target.style.paddingTop = 0;
|
||||
target.style.paddingBottom = 0;
|
||||
target.style.marginTop = 0;
|
||||
target.style.marginBottom = 0;
|
||||
target.offsetHeight;
|
||||
target.style.boxSizing = 'border-box';
|
||||
target.style.transitionProperty = 'height, margin, padding';
|
||||
target.style.transitionDuration = `${duration}ms`;
|
||||
target.style.height = `${height}px`;
|
||||
target.style.removeProperty('padding-top');
|
||||
target.style.removeProperty('padding-bottom');
|
||||
target.style.removeProperty('margin-top');
|
||||
target.style.removeProperty('margin-bottom');
|
||||
window.setTimeout(() => {
|
||||
//target.style.height = '100%'; // Зачем-то я хотел так сделать.....
|
||||
target.style.removeProperty('height');
|
||||
target.style.removeProperty('overflow');
|
||||
target.style.removeProperty('transition-duration');
|
||||
target.style.removeProperty('transition-property');
|
||||
}, duration);
|
||||
};
|
||||
|
||||
export const slideToggle = (target, duration = ANIMATION_DURATION) => {
|
||||
if (window.getComputedStyle(target).display === 'none') return slideDown(target, duration);
|
||||
return slideUp(target, duration);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
.layout {
|
||||
z-index: 1;
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.content {
|
||||
padding: 12px 50px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: auto;
|
||||
margin-bottom: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,301 @@
|
||||
@keyframes swing {
|
||||
0%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
10% {
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
}
|
||||
|
||||
.layout-main {
|
||||
.sidebar-main {
|
||||
.sidebar-main-menu {
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.menu-header {
|
||||
font-weight: 600;
|
||||
padding: 10px 25px;
|
||||
font-size: 0.8em;
|
||||
letter-spacing: 2px;
|
||||
transition: opacity 0.3s;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.menu-item {
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 38px;
|
||||
padding: 0 20px;
|
||||
color: $text-color;
|
||||
|
||||
.menu-icon {
|
||||
font-size: 1.2rem;
|
||||
width: 35px;
|
||||
min-width: 35px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
border-radius: 2px;
|
||||
transition: color 0.3s;
|
||||
i {
|
||||
// display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
font-size: 0.9em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex-grow: 1;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
.menu-prefix,
|
||||
.menu-suffix {
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
&:hover {
|
||||
.menu-title {
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
.menu-icon {
|
||||
color: $secondary-text-color;
|
||||
i {
|
||||
animation: swing ease-in-out 0.5s 1 alternate;
|
||||
}
|
||||
}
|
||||
&::after {
|
||||
border-color: $secondary-text-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.sub-menu {
|
||||
position: relative;
|
||||
> a {
|
||||
&::after {
|
||||
content: '';
|
||||
transition: transform 0.3s;
|
||||
border-right: 2px solid currentcolor;
|
||||
border-bottom: 2px solid currentcolor;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
> .sub-menu-list {
|
||||
padding-left: 20px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
z-index: 999;
|
||||
}
|
||||
&.open {
|
||||
> a {
|
||||
color: $secondary-text-color;
|
||||
&::after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
> a {
|
||||
.menu-title {
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
&::after {
|
||||
border-color: $secondary-text-color;
|
||||
}
|
||||
.menu-icon {
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
> ul > .sub-menu > .sub-menu-list {
|
||||
background-color: $secondary-bg-color;
|
||||
}
|
||||
|
||||
&.icon-shape-circle,
|
||||
&.icon-shape-rounded,
|
||||
&.icon-shape-square {
|
||||
.menu-item a .menu-icon {
|
||||
background-color: $secondary-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.icon-shape-circle .menu-item a .menu-icon {
|
||||
border-radius: 50%;
|
||||
}
|
||||
&.icon-shape-rounded .menu-item a .menu-icon {
|
||||
border-radius: 4px;
|
||||
}
|
||||
&.icon-shape-square .menu-item a .menu-icon {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.collapsed) {
|
||||
.sidebar-main-menu > ul {
|
||||
> .menu-item {
|
||||
&.sub-menu {
|
||||
> .sub-menu-list {
|
||||
visibility: visible !important;
|
||||
position: static !important;
|
||||
transform: translate(0, 0) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
.sidebar-main-menu > ul {
|
||||
> .menu-header {
|
||||
opacity: 0;
|
||||
}
|
||||
> .menu-item {
|
||||
> a {
|
||||
.menu-prefix,
|
||||
.menu-suffix {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
&.sub-menu {
|
||||
> a {
|
||||
&::after {
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: currentcolor;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
border: none;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
&:hover {
|
||||
&::after {
|
||||
background-color: $secondary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .sub-menu-list {
|
||||
transition: none !important;
|
||||
width: 200px;
|
||||
margin-left: 3px !important;
|
||||
border-radius: 4px;
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
&.active {
|
||||
> a {
|
||||
&::after {
|
||||
background-color: $secondary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.has-bg-image {
|
||||
.sidebar-main-menu {
|
||||
&.icon-shape-circle,
|
||||
&.icon-shape-rounded,
|
||||
&.icon-shape-square {
|
||||
.menu-item a .menu-icon {
|
||||
background-color: rgba($secondary-bg-color, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
&:not(.collapsed) {
|
||||
.sidebar-main-menu {
|
||||
> ul > .sub-menu > .sub-menu-list {
|
||||
background-color: rgba($secondary-bg-color, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.rtl {
|
||||
.sidebar-main {
|
||||
.sidebar-main-menu {
|
||||
.menu-item {
|
||||
a {
|
||||
.menu-icon {
|
||||
margin-left: 10px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.sub-menu {
|
||||
> a {
|
||||
&::after {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
|
||||
> .sub-menu-list {
|
||||
padding-left: 0;
|
||||
padding-right: 20px;
|
||||
}
|
||||
&.open {
|
||||
> a {
|
||||
&::after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
.sidebar-main-menu > ul {
|
||||
> .menu-item {
|
||||
&.sub-menu {
|
||||
a::after {
|
||||
right: auto;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
> .sub-menu-list {
|
||||
margin-left: -3px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
.sidebar-main {
|
||||
color: $text-color;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden !important;
|
||||
|
||||
.image-wrapper {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
> img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
}
|
||||
&.has-bg-image {
|
||||
.sidebar-layout {
|
||||
background-color: rgba($bg-color, 0.85);
|
||||
}
|
||||
.image-wrapper {
|
||||
display: block;
|
||||
opacity: 0.8;
|
||||
// filter: blur(3px);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-layout {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
background-color: $bg-color;
|
||||
z-index: 2;
|
||||
opacity: 0.85;
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: lighten($bg-color, 15);
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
background-color: $bg-color;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
height: $sidebar-header-height;
|
||||
min-height: $sidebar-header-height;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 22px;
|
||||
> span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.sidebar-content {
|
||||
flex-grow: 1;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.sidebar-footer {
|
||||
height: $sidebar-footer-height;
|
||||
min-height: $sidebar-footer-height;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
> span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
$text-color: #44b8eb;
|
||||
$secondary-text-color: #dee2ec;
|
||||
|
||||
$bg-color: #0c1e35;
|
||||
$secondary-bg-color: #0b1a2c;
|
||||
|
||||
$border-color: rgba(#535d7d, 0.3);
|
||||
|
||||
$sidebar-header-height: 40px;
|
||||
$sidebar-footer-height: 230px;
|
||||
@@ -0,0 +1,165 @@
|
||||
@import './variables_css-pro-layout.scss';
|
||||
|
||||
@mixin break-point {
|
||||
position: fixed;
|
||||
left: -$sidebar-width;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
&.collapsed {
|
||||
left: -$sidebar-collapsed-width;
|
||||
}
|
||||
&.toggled {
|
||||
left: 0;
|
||||
~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
~ .layout-main {
|
||||
.header {
|
||||
width: 100% !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$breakpoints: (
|
||||
'break-point-xs': $breakpoint-xs,
|
||||
'break-point-sm': $breakpoint-sm,
|
||||
'break-point-md': $breakpoint-md,
|
||||
'break-point-lg': $breakpoint-lg,
|
||||
'break-point-xl': $breakpoint-xl,
|
||||
'break-point-xxl': $breakpoint-xxl,
|
||||
);
|
||||
|
||||
@mixin break-point-rtl {
|
||||
left: auto;
|
||||
right: -$sidebar-width;
|
||||
&.collapsed {
|
||||
left: auto;
|
||||
right: -$sidebar-collapsed-width;
|
||||
}
|
||||
&.toggled {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin setBreakPoint($name, $value) {
|
||||
&.#{$name} {
|
||||
@media (max-width: $value) {
|
||||
@include break-point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-main {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
|
||||
&.has-sidebar {
|
||||
flex-direction: row;
|
||||
}
|
||||
.header {
|
||||
transition: width, 0.3s;
|
||||
height: $header-height;
|
||||
min-height: $header-height;
|
||||
position: relative;
|
||||
}
|
||||
.sidebar-main {
|
||||
width: $sidebar-width;
|
||||
min-width: $sidebar-width;
|
||||
transition: width, left, right, 0.3s;
|
||||
&.collapsed {
|
||||
width: $sidebar-collapsed-width;
|
||||
min-width: $sidebar-collapsed-width;
|
||||
}
|
||||
|
||||
@each $key, $value in $breakpoints {
|
||||
@include setBreakPoint($key, $value);
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
height: $footer-height;
|
||||
min-height: $footer-height;
|
||||
}
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(#000, 0.3);
|
||||
z-index: 99;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-toggler {
|
||||
display: none;
|
||||
|
||||
@each $key, $value in $breakpoints {
|
||||
&.#{$key} {
|
||||
@media (max-width: $value) {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed-sidebar {
|
||||
height: 100%;
|
||||
.sidebar {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
~ .layout-main {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed-header {
|
||||
.header {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
~ .layout-main,
|
||||
~ .content {
|
||||
margin-top: $header-height;
|
||||
}
|
||||
}
|
||||
&.fixed-sidebar {
|
||||
.header {
|
||||
width: calc(100% - #{$sidebar-width});
|
||||
}
|
||||
.sidebar.collapsed {
|
||||
~ .layout-main {
|
||||
.header {
|
||||
width: calc(100% - #{$sidebar-collapsed-width});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.rtl {
|
||||
direction: rtl;
|
||||
.sidebar {
|
||||
@each $key, $value in $breakpoints {
|
||||
&.#{$key} {
|
||||
@media (max-width: $value) {
|
||||
@include break-point-rtl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
$sidebar-width: 250px;
|
||||
$sidebar-collapsed-width: 80px;
|
||||
|
||||
/*@import 'css-pro-layout/dist/scss/css-pro-layout.scss';*/
|
||||
@import './css-pro-layout.scss';
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
||||
/*@import '../../public//assets//remixicon/remixicon.css';*/
|
||||
@import './variables';
|
||||
@import './layout';
|
||||
@import './sidebar';
|
||||
@import './menu';
|
||||
|
||||
/*
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
color: #3f4750;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
*/
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
#btn-collapse {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-main {
|
||||
.sidebar-main {
|
||||
.pro-sidebar-logo {
|
||||
color: #ffa801;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> div {
|
||||
width: 45px;
|
||||
min-width: 45px;
|
||||
height: 25px;
|
||||
min-height: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
background-color: #ffa801;
|
||||
margin-right: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
> h5 {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 22px;
|
||||
line-height: 25px;
|
||||
transition: opacity 0.3s;
|
||||
opacity: 1;
|
||||
margin: 0 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
/* font-size: 0.8em; */
|
||||
padding: 20px 0;
|
||||
border-radius: 8px;
|
||||
width: 180px;
|
||||
min-width: 190px;
|
||||
margin: 0 auto;
|
||||
background-color: #162d4a;
|
||||
img.react-logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-collapser {
|
||||
transition: left, right, 0.3s;
|
||||
position: fixed;
|
||||
left: calc(#{$sidebar-width} - 20px);
|
||||
top: 40px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background-color: #00829f;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2em;
|
||||
transform: translateX(50%);
|
||||
z-index: 111;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
box-shadow: 1px 1px 4px $bg-color;
|
||||
}
|
||||
|
||||
&.has-bg-image {
|
||||
.footer-box {
|
||||
/* background-color: rgba(#162d4a, 0.7); */
|
||||
background-color: #34495e;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
.pro-sidebar-logo {
|
||||
> h5 {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.footer-box {
|
||||
display: none;
|
||||
}
|
||||
.sidebar-collapser {
|
||||
left: calc(#{$sidebar-collapsed-width} - 20px);
|
||||
i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.25em 0.4em;
|
||||
font-size: 75%;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: 0.25rem;
|
||||
color: #fff;
|
||||
background-color: #6c757d;
|
||||
|
||||
&.primary {
|
||||
background-color: #ab2dff;
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: #079b0b;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-toggler {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
a {
|
||||
margin: 0 10px;
|
||||
color: #3f4750;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
$sidebar-width: 280px !default;
|
||||
$sidebar-collapsed-width: 80px !default;
|
||||
$header-height: 64px !default;
|
||||
$footer-height: 64px !default;
|
||||
|
||||
$breakpoint-xs: 480px !default;
|
||||
$breakpoint-sm: 576px !default;
|
||||
$breakpoint-md: 768px !default;
|
||||
$breakpoint-lg: 992px !default;
|
||||
$breakpoint-xl: 1200px !default;
|
||||
$breakpoint-xxl: 1600px !default;
|
||||
@@ -0,0 +1,47 @@
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
//const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin(),
|
||||
// new CopyWebpackPlugin({
|
||||
// patterns: [{ from: 'public' }],
|
||||
// }),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: { loader: 'babel-loader' },
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.(css|scss|sass|less)$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
'css-loader',
|
||||
'sass-loader',
|
||||
// 'less-loader',
|
||||
'postcss-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|svg|jpg|gif)$/,
|
||||
use: ['file-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
use: ['file-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
mode: 'production',
|
||||
target: 'web',
|
||||
devtool: 'source-map',
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.join(__dirname, 'public'),
|
||||
},
|
||||
},
|
||||
};
|
||||
9
web/skins/classic/assets/swiped-events/dist/swiped-events.min.js
vendored
Normal file
9
web/skins/classic/assets/swiped-events/dist/swiped-events.min.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* swiped-events.js - v1.2.0
|
||||
* Pure JavaScript swipe events
|
||||
* https://github.com/john-doherty/swiped-events
|
||||
* @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
|
||||
* @author John Doherty <www.johndoherty.info>
|
||||
* @license MIT
|
||||
*/
|
||||
!function(t,e){"use strict";"function"!=typeof t.CustomEvent&&(t.CustomEvent=function(t,n){n=n||{bubbles:!1,cancelable:!1,detail:void 0};var a=e.createEvent("CustomEvent");return a.initCustomEvent(t,n.bubbles,n.cancelable,n.detail),a},t.CustomEvent.prototype=t.Event.prototype),e.addEventListener("touchstart",function(t){if("true"===t.target.getAttribute("data-swipe-ignore"))return;l=t.target,r=Date.now(),n=t.touches[0].clientX,a=t.touches[0].clientY,u=0,i=0,o=t.touches.length},!1),e.addEventListener("touchmove",function(t){if(!n||!a)return;var e=t.touches[0].clientX,r=t.touches[0].clientY;u=n-e,i=a-r},!1),e.addEventListener("touchend",function(t){if(l!==t.target)return;var c=parseInt(s(l,"data-swipe-threshold","20"),10),d=s(l,"data-swipe-unit","px"),p=parseInt(s(l,"data-swipe-timeout","500"),10),h=Date.now()-r,v="",b=t.changedTouches||t.touches||[];"vh"===d&&(c=Math.round(c/100*e.documentElement.clientHeight));"vw"===d&&(c=Math.round(c/100*e.documentElement.clientWidth));Math.abs(u)>Math.abs(i)?Math.abs(u)>c&&h<p&&(v=u>0?"swiped-left":"swiped-right"):Math.abs(i)>c&&h<p&&(v=i>0?"swiped-up":"swiped-down");if(""!==v){var E={dir:v.replace(/swiped-/,""),touchType:(b[0]||{}).touchType||"direct",fingers:o,xStart:parseInt(n,10),xEnd:parseInt((b[0]||{}).clientX||-1,10),yStart:parseInt(a,10),yEnd:parseInt((b[0]||{}).clientY||-1,10)};l.dispatchEvent(new CustomEvent("swiped",{bubbles:!0,cancelable:!0,detail:E})),l.dispatchEvent(new CustomEvent(v,{bubbles:!0,cancelable:!0,detail:E}))}n=null,a=null,r=null},!1);var n=null,a=null,u=null,i=null,r=null,l=null,o=0;function s(t,n,a){for(;t&&t!==e.documentElement;){var u=t.getAttribute(n);if(u)return u;t=t.parentNode}return a}}(window,document);
|
||||
@@ -5,3 +5,12 @@ https://unpkg.com/@panzoom/panzoom@4.5.1/dist/panzoom.min.js
|
||||
***********************************
|
||||
gridstack - v11.1.2 on Dec 9, 2024 (Newer versions have a significant bug: https://github.com/gridstack/gridstack.js/issues/2978)
|
||||
https://github.com/gridstack/gridstack.js
|
||||
***********************************
|
||||
pro-sidebar-template - Feb 1, 2023 with minor changes IgorA100
|
||||
https://github.com/azouaoui-med/pro-sidebar-template
|
||||
***********************************
|
||||
swiped-events - v. 1.2.0 Apr 27, 2024
|
||||
https://github.com/john-doherty/swiped-events
|
||||
***********************************
|
||||
mb.extruder Oct 24, 2018 with magor changes IgorA100
|
||||
https://github.com/pupunzi/jquery.mb.extruder
|
||||
|
||||
323
web/skins/classic/css/base/sidebar.css
Normal file
323
web/skins/classic/css/base/sidebar.css
Normal file
@@ -0,0 +1,323 @@
|
||||
.layout-main .sidebar-main a.text-success:focus,
|
||||
.layout-main .sidebar-main a.text-success:hover { /* FIX bootstrap on a dark background*/
|
||||
color: #007bff !important;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main.collapsed .hidden-for-collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* +++ Scrollbar for menu in left sidebar NEEDS MORE COMPACT */
|
||||
#navbar-container,
|
||||
.layout-main .sidebar-main .sidebar-layout,
|
||||
.layout-main .sidebar-main .sidebar-content::-webkit-scrollbar-track,
|
||||
.layout-main .sidebar-main .sidebar-layout::-webkit-scrollbar-track ,
|
||||
.layout-main .sidebar-main .extruder-wrapper::-webkit-scrollbar-track ,
|
||||
.layout-main .sidebar-main .extruder-content .filter-block::-webkit-scrollbar-track {
|
||||
background-color: var(--backgroundMediumDark); /* #485460 */
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-content::-webkit-scrollbar-thumb,
|
||||
.layout-main .sidebar-main .sidebar-layout::-webkit-scrollbar-thumb,
|
||||
.layout-main .sidebar-main .extruder-wrapper::-webkit-scrollbar-thumb,
|
||||
.layout-main .sidebar-main .extruder-content .filter-block::-webkit-scrollbar-thumb {
|
||||
background-color: var(--sliderBG);
|
||||
border-radius: 6px;
|
||||
border: 0px solid var(--scrollbarBG);
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-content::-webkit-scrollbar,
|
||||
.layout-main .sidebar-main .sidebar-layout::-webkit-scrollbar,
|
||||
.layout-main .sidebar-main .extruder-wrapper::-webkit-scrollbar,
|
||||
.layout-main .sidebar-main .extruder-content .filter-block::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-layout:hover::-webkit-scrollbar-thumb { /* this is also defined in the _sidebar.scss file */
|
||||
background-color: var(--sliderBG);
|
||||
}
|
||||
/* --- Scrollbar for menu in left sidebar */
|
||||
|
||||
.layout-main .sidebar-main .sidebar-post-header {
|
||||
padding: 5px 0 5px 0;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-main-menu,
|
||||
.layout-main .sidebar-main .sidebar-post-header {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-layout .sidebar-content {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main.has-bg-image:not(.collapsed) .sidebar-main-menu > ul > .sub-menu > .sub-menu-list {
|
||||
background-color: #34495e;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-main-menu .menu-item a .menu-title, /* FIX _menu.scss */
|
||||
.layout-main .sidebar-main .sidebar-post-header .menu-item a .menu-title {
|
||||
/*font-size: 0.9rem;*/
|
||||
font-size: inherit;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-post-header .menu-item a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.layout-main .sidebar-main .sidebar-post-header .menu-item a .menu-icon {
|
||||
font-size: 1.2rem;
|
||||
width: 35px;
|
||||
min-width: 35px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
border-radius: 2px;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
/* +++ MontageRewiev Filter Alignment */
|
||||
.layout-main .sidebar-main .chosen-container {
|
||||
text-align: left;
|
||||
min-width: 11em;
|
||||
width: 100% !important;
|
||||
}
|
||||
/* --- */
|
||||
|
||||
body.sticky .content-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-main {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* We don't need to see the filter and other things (that we cut out). */
|
||||
.montagereview-page .content-main .controlHeader,
|
||||
.montagereview-page .content-main #fieldsTable,
|
||||
.console-page .content-main #fbpanel,
|
||||
.console-page a[data-flip-control-object="#fbpanel"], /* Filter visibility control button */
|
||||
.montage-page .content-main #filters_form,
|
||||
.watch-page .content-main .controlHeader,
|
||||
.report_event_audit-page #content form,
|
||||
.events-page .content-main #fieldsTable,
|
||||
.events-page a[data-flip-control-object="#fieldsTable"], /* Filter visibility control button */
|
||||
.options-page .content-main #sidebar,
|
||||
.navbar-brand,
|
||||
#navbar-one {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#monitorList {
|
||||
overflow-y: auto; /* CHECK!!! PROBABLY THIS SHOULD ALWAYS BE USED, AND NOT JUST FOR STICK MODE!!! */
|
||||
}
|
||||
|
||||
/* Align the entire bar to the left side */
|
||||
.navbars {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#btn-collapse {
|
||||
top: 11px;
|
||||
}
|
||||
|
||||
#wrapperBtnCloseExtruder{ /* Extruder block close button on mobile devices */
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
/* +++ Manage the collapse/expand menu button for mobile devices with hidden menu */
|
||||
#btn-collapse {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#sidebarMain.sidebar-main:not(.toggled) #btn-collapse {
|
||||
left: -50px; /* Ideally, you need to set the value here as for ".layout-main .sidebar-main.break-point-lg" or -250 or -80. But even now the icon motion looks very good */
|
||||
}
|
||||
/* --- */
|
||||
|
||||
#extruderLeft {
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
#wrapperBtnCloseExtruder{
|
||||
position: relative;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.extruder-content > .text:first-child {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 500px) {
|
||||
.layout-main .sidebar-main .sidebar-content,
|
||||
.layout-main .sidebar-main .sidebar-footer { /* Sidebar is not divided into Header, Footer and content. Everything is one and everything is scrollable */
|
||||
display: contents;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-toggler { /* also set in pro-sidebar-template/src/styles/styles.scss */
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#navbar-two { /* THE PANEL MUST ALWAYS BE VISIBLE, OTHERWISE IT COULD BE HIDDEN BY A BUTTON (id="flip") */
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* Choice at the bar */
|
||||
#panel .dropdown-menu.show.overflown {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
#panel .dropdown-menu.show:not(.overflown) {
|
||||
display: block;
|
||||
top: 27px;
|
||||
}
|
||||
|
||||
/* +++ THIS IS REMAINING FROM THE TOP STATUS LINE */
|
||||
#reload {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
padding: 10px 5px 10px 15px
|
||||
}
|
||||
|
||||
@media (max-width: 992px) { /* moment hamburger menu button appears */
|
||||
#reload {
|
||||
left: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
#reload > ul,
|
||||
#reload > ul > ul,
|
||||
#reload > ul > li { /* remove the first part with the divas */
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#reload > ul:last-child{ /* the last element when scrolling should have an indent */
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
#reload::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
#reload::-webkit-scrollbar-thumb {
|
||||
border: 0px solid;
|
||||
}
|
||||
|
||||
.high-scroll-bar::-webkit-scrollbar {
|
||||
width: 7px !important;
|
||||
height: 7px !important;
|
||||
}
|
||||
/* --- THIS IS REMAINING FROM THE TOP STATUS LINE */
|
||||
|
||||
|
||||
#sidebarMain.collapsed .sub-menu-list {
|
||||
height: 0; /* Otherwise it will flicker when the page loads. */
|
||||
}
|
||||
|
||||
/* Set submenu to scroll vertically (for narrow option) when submenu is displayed on the side */
|
||||
body #sidebarMain .sub-menu-list {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* +++ TRANSFERRED FILTERS */
|
||||
.extruder-wrapper span.term .term-label-wrapper,
|
||||
.extruder-wrapper span.term label {
|
||||
display: flex !important;
|
||||
text-align: left !important;
|
||||
width: auto !important;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.extruder-wrapper span.term .term-value-wrapper {
|
||||
display: flex !important;
|
||||
justify-content: flex-end !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.extruder-wrapper span.term,
|
||||
.extruder-wrapper span.term .term-value-wrapper input,
|
||||
.extruder-wrapper span.term > span { /* Aligning input fields */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.extruder-wrapper span.term > span:first-child{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.extruder-content {
|
||||
background-color: var(--backgroundMediumDark);
|
||||
}
|
||||
|
||||
.extruder-content > .text {
|
||||
overflow: visible !important; /* Allows dropdowns to extend beyond the block if there is space on the screen */
|
||||
}
|
||||
|
||||
.extruder-content .filter-block {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.extruder-content > .text .term {
|
||||
flex-direction: row;
|
||||
margin-left: 0;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 564px) {
|
||||
.extruder-content span.term {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.extruder-content button .material-icons {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.extruder .extruder-content .chosen-container .chosen-single,
|
||||
.extruder-wrapper span.term .term-value-wrapper input {
|
||||
height: 27px !important;
|
||||
}
|
||||
|
||||
/* Clear Filter Button Select Multiple Selection */
|
||||
.extruder .extruder-content .btn-term-remove-all {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
width: auto;
|
||||
padding-left: 10px;
|
||||
max-height: 35px;
|
||||
}
|
||||
/* --- TRANSFERRED FILTERS */
|
||||
|
||||
/* !HACK! Otherwise the height of the parent block will be calculated based on the height of the drop-down list, even if the selection is not active! */
|
||||
div:not(.chosen-container-active) > .chosen-drop {
|
||||
display: none;
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
--sliderBG: #C1C1C1;
|
||||
--alarmBG: #FFC0C0;
|
||||
--alarmText: inherit;
|
||||
--backgroundMediumDark: #485460;
|
||||
}
|
||||
|
||||
html,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
--scrollbarBG: #CFD8DC;
|
||||
--sliderBG: #95AFC0;
|
||||
--alarmBG: #352424;
|
||||
--backgroundMediumDark: #485460;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
|
||||
$useOldMenuView = (isset($_COOKIE['zmUseOldMenuView']) and $_COOKIE["zmUseOldMenuView"] === 'true') ? true : false;
|
||||
|
||||
function xhtmlHeaders($file, $title) {
|
||||
xhtmlHeadersStart($file, $title);
|
||||
xhtmlHeadersEnd();
|
||||
@@ -117,6 +119,14 @@ if ( $css != 'base' )
|
||||
'css/'.$css.'/jquery-ui-theme.css',
|
||||
));
|
||||
|
||||
global $useOldMenuView;
|
||||
if (!$useOldMenuView) {
|
||||
echo output_link_if_exists(array(
|
||||
'/assets/pro-sidebar-template/dist/main.css',
|
||||
'/css/base/sidebar.css',
|
||||
));
|
||||
}
|
||||
|
||||
if ( $basename == 'watch' ) {
|
||||
echo output_link_if_exists(array('/css/base/views/control.css'));
|
||||
if ( $css != 'base' )
|
||||
@@ -146,8 +156,11 @@ function xhtmlHeadersEnd() {
|
||||
|
||||
// Outputs an opening body tag, and any additional content that should go at the very top, like warnings and error messages.
|
||||
function getBodyTopHTML() {
|
||||
global $view;
|
||||
//Needed for more flexible global governance
|
||||
$classHTML = ' class="'.$view.'-page'.((defined('ZM_WEB_NAVBAR_STICKY') and ZM_WEB_NAVBAR_STICKY) ? ' sticky"' : '"');
|
||||
echo '
|
||||
<body'.((defined('ZM_WEB_NAVBAR_STICKY') and ZM_WEB_NAVBAR_STICKY) ? ' class="sticky"' : '').'>
|
||||
<body data-swipe-threshold="10" data-swipe-unit="vw" data-swipe-timeout="300"'.$classHTML.'>
|
||||
<noscript>
|
||||
<div style="background-color:red;color:white;font-size:x-large;">
|
||||
'. validHtmlStr(ZM_WEB_TITLE) .' requires Javascript. Please enable Javascript in your browser for this site.
|
||||
@@ -159,8 +172,200 @@ function getBodyTopHTML() {
|
||||
if ( $error_message ) {
|
||||
echo '<div id="error">'.$error_message.'</div>';
|
||||
}
|
||||
global $useOldMenuView;
|
||||
if ($useOldMenuView !== true) {
|
||||
getSidebarTopHTML();
|
||||
}
|
||||
} // end function getBodyTopHTML
|
||||
|
||||
function buildMenuItem($viewItemName, $id, $itemName, $href, $icon, $classNameForTag_A = '', $subMenu = '') {
|
||||
global $view;
|
||||
/* Highlighting the active menu section */
|
||||
if ($viewItemName == 'watch') {
|
||||
$activeClass = ($view == $viewItemName && (isset($_REQUEST['cycle']) && $_REQUEST['cycle'] == "true")) ? ' active' : '';
|
||||
} else {
|
||||
$activeClass = $view == $viewItemName ? ' active' : '';
|
||||
}
|
||||
$itemName = translate($itemName);
|
||||
$result = '
|
||||
<li id="' . $id . '" class="menu-item '.$activeClass.'">
|
||||
<a href="' . $href . '" class="' . $classNameForTag_A . '">
|
||||
<span class="menu-icon"><i class="material-icons">' . $icon . '</i></span>
|
||||
<span class="menu-title">'.$itemName.'</span>
|
||||
</a>
|
||||
</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function buildSidebarMenu() {
|
||||
global $view;
|
||||
global $useOldMenuView;
|
||||
global $user;
|
||||
if ( $user and $user->Username() ) {
|
||||
$menuForAuthUser = '
|
||||
<li class="menu-header"><span> GENERAL </span></li> ' .
|
||||
getConsoleHTML($forLeftBar = true) .
|
||||
getMontageHTML($view, $forLeftBar = true) .
|
||||
getCycleHTML($view, $forLeftBar = true) .
|
||||
getMontageReviewHTML($view, $forLeftBar = true) .
|
||||
getEventsHTML($view, $forLeftBar = true) .
|
||||
getOptionsHTML($forLeftBar = true) .
|
||||
getLogHTML($forLeftBar = true) .
|
||||
getDevicesHTML($forLeftBar = true) .
|
||||
getGroupsHTML($view, $forLeftBar = true) .
|
||||
getFilterHTML($view, $forLeftBar = true) .
|
||||
getSnapshotsHTML($view, $forLeftBar = true) .
|
||||
getReportsHTML($view, $forLeftBar = true) .
|
||||
getRprtEvntAuditHTML($view, $forLeftBar = true) .
|
||||
getMapHTML($view, $forLeftBar = true)
|
||||
;
|
||||
} else { // USER IS NOT AUTHORIZED!
|
||||
$menuForAuthUser = '';
|
||||
}
|
||||
$menu = '
|
||||
<nav class="sidebar-main-menu open-current-submenu">
|
||||
<ul>
|
||||
' . $menuForAuthUser . '
|
||||
<li class="menu-header" style="padding-top: 20px"><span> OTHER </span></li>
|
||||
<li class="menu-item">
|
||||
<a href="http://zoneminder.com/" target="_blank">
|
||||
<span class="menu-icon">
|
||||
<i class="material-icons">videocam</i>
|
||||
</span>
|
||||
<span class="menu-title">' . translate("ZoneMinder") . '</span>
|
||||
<span class="menu-suffix">
|
||||
<span class="badge secondary"><i class="material-icons md-14">thumb_up</i></span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="http://zoneminder.readthedocs.org/en/latest/" target="_blank">
|
||||
<span class="menu-icon">
|
||||
<i class="material-icons">description</i>
|
||||
</span>
|
||||
<span class="menu-title">' . translate("Documentation") . '</span>
|
||||
<!--<span class="menu-suffix">
|
||||
<span class="badge secondary">Beta</span>
|
||||
</span>-->
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://zmninja.zoneminder.com/" target="_blank">
|
||||
<span class="menu-icon">
|
||||
<i class="material-icons">face_5</i>
|
||||
</span>
|
||||
<span class="menu-title">' . translate("zmNinja") . '</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://wiki.zoneminder.com/" target="_blank">
|
||||
<span class="menu-icon">
|
||||
<i class="material-icons">article</i>
|
||||
</span>
|
||||
<span class="menu-title">' . translate("Wiki") . '</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://forums.zoneminder.com/" target="_blank">
|
||||
<span class="menu-icon">
|
||||
<i class="material-icons">forum</i>
|
||||
</span>
|
||||
<span class="menu-title">' . translate("Forums") . '</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://zoneminder-chat.slack.com/" target="_blank">
|
||||
<span class="menu-icon">
|
||||
<i class="material-icons">chat</i>
|
||||
</span>
|
||||
<span class="menu-title">' . translate("Slack") . '</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-header hidden-for-collapsed" style="padding-top: 20px">
|
||||
<label for="useOldMenuView" class="control-label text-md-right">' . translate("USE OLD MENU VIEW") . '</label>
|
||||
<input type="checkbox" name="useOldMenuView" id="useOldMenuView" value="1"' . ( $useOldMenuView ? ' checked="checked"' : '') . '/>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
';
|
||||
return $menu;
|
||||
}
|
||||
|
||||
function getSidebarTopHTML() {
|
||||
global $skin;
|
||||
global $user;
|
||||
global $running;
|
||||
|
||||
$blockExtruder = '
|
||||
<div id="extruderLeft">
|
||||
<div id="contextExtruderLeft" class="text">
|
||||
<! -- Pull-out panel FILLED VIA JS -->
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
$block = '
|
||||
<div class="layout-main has-sidebar fixed-sidebar fixed-header">
|
||||
<aside id="sidebarMain" class="sidebar-main break-point-lg has-bg-image '. (( isset($_COOKIE['zmSidebarMainCollapse']) and $_COOKIE["zmSidebarMainCollapse"] === 'true' ) ? "collapsed" : "") . '">
|
||||
' . $blockExtruder . '
|
||||
<a id="btn-collapse" class="sidebar-collapser"><i class="material-icons">chevron_left</i></a>
|
||||
<div class="image-wrapper">
|
||||
<img src="skins/'.$skin.'/assets/pro-sidebar-template/assets/images/sidebar-bg.jpg" alt="sidebar background" />
|
||||
</div>
|
||||
<div class="sidebar-layout">
|
||||
<div class="sidebar-header">
|
||||
<div class="pro-sidebar-logo">
|
||||
<div>ZM</div>
|
||||
<h5>ZoneMinder</h5>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End of header, before scrolling menu -->
|
||||
<div id="menuControlModule" class="sidebar-post-header">
|
||||
<!-- FILLED VIA JS -->
|
||||
</div>
|
||||
<!-- Start of scrolling menu -->
|
||||
<div class="sidebar-content">
|
||||
' . buildSidebarMenu() . '
|
||||
</div>
|
||||
<div class="sidebar-footer hidden-for-collapsed">
|
||||
<div class="footer-box">
|
||||
<div>
|
||||
' . getAccountCircleHTML($skin, $user, $forLeftBar = true) . '
|
||||
</div>
|
||||
<div style="padding: 0 10px">
|
||||
<span style="display: block; margin-bottom: 10px">
|
||||
<ul id="versionSidebar">
|
||||
' . getZMVersionHTML() . '
|
||||
</ul>
|
||||
</span>
|
||||
<ul id="statusSidebar">
|
||||
' . getStatusBtnHTML(runtimeStatus($running)) . '
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div id="overlay" class="overlay"></div>
|
||||
<div class="content-main">
|
||||
';
|
||||
echo $block;
|
||||
} // end function getSidebarTopHTML
|
||||
|
||||
function getSidebarBottomHTML() {
|
||||
global $skin;
|
||||
$block = '
|
||||
<div class="overlay"></div>
|
||||
</div> <!-- class="content-main" -->
|
||||
</div> <!-- class="layout-main has-sidebar fixed-sidebar fixed-header" -->
|
||||
<style>
|
||||
|
||||
</style>
|
||||
';
|
||||
echo $block;
|
||||
} // end function getSidebarBottomHTML
|
||||
|
||||
function getNavBarHTML() {
|
||||
# Provide a facility to turn off the headers if you put navbar=0 into the url
|
||||
if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar'] == '0' )
|
||||
@@ -298,9 +503,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $skin)
|
||||
echo getMapHTML($view);
|
||||
echo getAdditionalLinksHTML($view);
|
||||
echo getHeaderFlipHTML();
|
||||
echo '</ul></div><div id="accountstatus">
|
||||
';
|
||||
|
||||
echo '</ul></div><div id="accountstatus">';
|
||||
echo '<ul class="nav navbar-nav justify-content-end align-self-start flex-grow-1">';
|
||||
echo getAccountCircleHTML($skin, $user);
|
||||
echo getStatusBtnHTML($status);
|
||||
@@ -317,27 +520,12 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $skin)
|
||||
<?php
|
||||
|
||||
// *** Build the statistics shown on the navigation bar ***
|
||||
?>
|
||||
<div id="reload" class="container-fluid">
|
||||
<ul id="Bandwidth" class="navbar-nav justify-content-start">
|
||||
<?php echo getBandwidthHTML($bandwidth_options, $user) ?>
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav list-inline justify-content-center">
|
||||
<?php
|
||||
echo getSysLoadHTML();
|
||||
echo getCpuUsageHTML();
|
||||
echo getDbConHTML();
|
||||
echo getStorageHTML();
|
||||
echo getRamHTML();
|
||||
?>
|
||||
</ul>
|
||||
|
||||
<ul id="Version" class="nav navbar-nav justify-content-end">
|
||||
<?php echo getZMVersionHTML() ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
global $useOldMenuView;
|
||||
if ($useOldMenuView !== true) {
|
||||
echo buildStatisticsBar($forLeftBar = true);
|
||||
} else {
|
||||
echo buildStatisticsBar($forLeftBar = false);
|
||||
}
|
||||
?>
|
||||
</div><!-- End Collapsible Panel -->
|
||||
</nav><!-- End Second Navbar -->
|
||||
@@ -351,6 +539,46 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $skin)
|
||||
<?php
|
||||
} // end function getNormalNavBarHTML()
|
||||
|
||||
function buildStatisticsBar($forLeftBar = false) {
|
||||
// *** Build the statistics shown on the navigation bar ***
|
||||
global $bandwidth_options;
|
||||
global $user;
|
||||
$block = '';
|
||||
if ($forLeftBar) {
|
||||
// Mobile menu hamburger button
|
||||
$block .= '
|
||||
<div style="left: 5px; top: 10px; position: absolute;">
|
||||
<a id="btn-toggle" href="#" class="sidebar-toggler break-point-lg">
|
||||
<i class="material-icons">menu</i>
|
||||
</a>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
|
||||
$block .= '
|
||||
<div id="reload" class="container-fluid">
|
||||
<ul id="Bandwidth" class="navbar-nav justify-content-start">
|
||||
' . getBandwidthHTML($bandwidth_options, $user) .'
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav list-inline justify-content-center">
|
||||
'.
|
||||
getSysLoadHTML().
|
||||
getCpuUsageHTML().
|
||||
getDbConHTML().
|
||||
getStorageHTML().
|
||||
getRamHTML()
|
||||
.'
|
||||
</ul>
|
||||
|
||||
<ul id="Version" class="nav navbar-nav justify-content-end">
|
||||
' . getZMVersionHTML() . '
|
||||
</ul>
|
||||
</div>
|
||||
';
|
||||
return $block;
|
||||
}
|
||||
|
||||
//
|
||||
// A new, slimmer navigation bar, permanently collapsed into a dropdown
|
||||
//
|
||||
@@ -464,7 +692,7 @@ function getSysLoadHTML() {
|
||||
$thisServer->ReadStats();
|
||||
|
||||
$result .= '<li id="getSysLoadHTML" class="Load nav-item mx-2">';
|
||||
$result .= '<i class="material-icons md-18" style="display: inline-block;">trending_up</i>';
|
||||
$result .= '<i class="material-icons md-18">trending_up</i>';
|
||||
$result .= ' '.translate('Load').': '.number_format($thisServer->CpuLoad, 2, '.', '');
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
}
|
||||
@@ -481,7 +709,7 @@ function getDbConHTML() {
|
||||
$class = ( $percent_used > 90 ) ? ' text-warning' : '';
|
||||
|
||||
$result .= '<li id="getDbConHTML" class="nav-item dropdown mx-2' .$class. '">'.PHP_EOL;
|
||||
$result .= '<i class="material-icons md-18 mr-1" style="display: inline-block;">storage</i>'.PHP_EOL;
|
||||
$result .= '<i class="material-icons md-18 mr-1">storage</i>'.PHP_EOL;
|
||||
$result .= translate('DB'). ': ' .$connections. '/' .$max_connections.PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
|
||||
@@ -529,7 +757,7 @@ function getStorageHTML() {
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
} else {
|
||||
$result .= '<li id="getStorageHTML" class="nav-item dropdown mx-2">'.PHP_EOL;
|
||||
$result .= '<a class="dropdown-toggle mr-2 '.$class.'" href="#" id="dropdown_storage" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="material-icons md-18 mr-1" style="display: inline-block;">folder_shared</i>Storage</a>'.PHP_EOL;
|
||||
$result .= '<a class="dropdown-toggle mr-2 '.$class.'" href="#" id="dropdown_storage" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="material-icons md-18 mr-1">folder_shared</i>Storage</a>'.PHP_EOL;
|
||||
$result .= '<div class="dropdown-menu" aria-labelledby="dropdown_storage">'.PHP_EOL;
|
||||
|
||||
foreach ( $storage_areas as $area ) {
|
||||
@@ -625,7 +853,7 @@ function getBandwidthHTML($bandwidth_options, $user) {
|
||||
$result = '';
|
||||
if (count($bandwidth_options) > 1) {
|
||||
$result .= '<li id="getBandwidthHTML" class="nav-item dropdown mx-2">'.PHP_EOL;
|
||||
$result .= '<a class="dropdown-toggle mr-2" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="dropdown_bandwidth"><i class="material-icons md-18 mr-1" style="display: inline-block;">network_check</i>'.translate($bandwidth_options[$_COOKIE['zmBandwidth']]).'</a>'.PHP_EOL;
|
||||
$result .= '<a class="dropdown-toggle mr-2" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="dropdown_bandwidth"><i class="material-icons md-18 mr-1">network_check</i>'.translate($bandwidth_options[$_COOKIE['zmBandwidth']]).'</a>'.PHP_EOL;
|
||||
|
||||
$result .= '<div class="dropdown-menu" aria-labelledby="dropdown_bandwidth">'.PHP_EOL;
|
||||
if ( isset($bandwidth_options['high']) )
|
||||
@@ -696,42 +924,142 @@ function getNavBrandHTML() {
|
||||
} else {
|
||||
$result .= '<a id="getNavBrandHTML" href="' .validHtmlStr(ZM_HOME_URL). '" target="' .validHtmlStr(ZM_WEB_TITLE). '">' .ZM_HOME_CONTENT. '</a>'.PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
global $useOldMenuView;
|
||||
if ($useOldMenuView) {
|
||||
$result .= '
|
||||
<div id="blockUseOldMenuView" style="display: flex;">
|
||||
<label style="font-size: 14px; color: white;" for="useOldMenuView" class="control-label text-md-right">' . translate("Use old menu view") . '</label>
|
||||
<input type="checkbox" name="useOldMenuView" id="useOldMenuView" value="1"' . ( $useOldMenuView ? ' checked="checked"' : '') . '/>
|
||||
</div>
|
||||
'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Console menu item
|
||||
function getConsoleHTML() {
|
||||
function getConsoleHTML($forLeftBar = false) {
|
||||
global $user;
|
||||
$result = '';
|
||||
|
||||
if (count($user->viewableMonitorIds()) or !ZM\Monitor::find_one()) {
|
||||
$result .= '<li id="getConsoleHTML" class="nav-item"><a class="nav-link" href="?view=console">'.translate('Console').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'console',
|
||||
$id = 'getConsoleHTML',
|
||||
$itemName = 'Console',
|
||||
$href = '?view=console',
|
||||
$icon = 'dashboard',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getConsoleHTML" class="nav-item"><a class="nav-link" href="?view=console">'.translate('Console').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Options menu item
|
||||
function getOptionsHTML() {
|
||||
function getOptionsHTML($forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('System') ) {
|
||||
$result .= '<li id="getOptionsHTML" class="nav-item"><a class="nav-link" href="?view=options">'.translate('Options').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
// Copied from web/skins/classic/views/options.php
|
||||
// When using the old top menu, the list of options pages is still generated in the views/options.php file.
|
||||
global $view;
|
||||
|
||||
$tabs = array();
|
||||
if (!defined('ZM_FORCE_CSS_DEFAULT') or !defined('ZM_FORCE_SKIN_DEFAULT'))
|
||||
$tabs['skins'] = translate('Display');
|
||||
$tabs['system'] = translate('System');
|
||||
$tabs['auth'] = translate('Authentication');
|
||||
$tabs['config'] = translate('Config');
|
||||
if (defined('ZM_PATH_DNSMASQ_CONF') and ZM_PATH_DNSMASQ_CONF) {
|
||||
$tabs['dnsmasq'] = translate('DHCP');
|
||||
}
|
||||
$tabs['API'] = translate('API');
|
||||
$tabs['servers'] = translate('Servers');
|
||||
$tabs['storage'] = translate('Storage');
|
||||
$tabs['web'] = translate('Web');
|
||||
$tabs['images'] = translate('Images');
|
||||
$tabs['logging'] = translate('Logging');
|
||||
$tabs['network'] = translate('Network');
|
||||
$tabs['mail'] = translate('Email');
|
||||
$tabs['upload'] = translate('Upload');
|
||||
$tabs['x10'] = translate('X10');
|
||||
$tabs['highband'] = translate('HighBW');
|
||||
$tabs['medband'] = translate('MediumBW');
|
||||
$tabs['lowband'] = translate('LowBW');
|
||||
$tabs['users'] = translate('Users');
|
||||
$tabs['groups'] = translate('Groups');
|
||||
$tabs['control'] = translate('Control');
|
||||
$tabs['privacy'] = translate('Privacy');
|
||||
$tabs['MQTT'] = translate('MQTT');
|
||||
$tabs['telemetry'] = translate('Telemetry');
|
||||
$tabs['version'] = translate('Versions');
|
||||
|
||||
$view_ = 'options';
|
||||
//$tab = isset($_REQUEST['tab']) ? validHtmlStr($_REQUEST['tab']) : 'system';
|
||||
$tab = isset($_REQUEST['tab']) ? validHtmlStr($_REQUEST['tab']) : '';
|
||||
|
||||
$subMenuOptions = '
|
||||
<div class="sub-menu-list">
|
||||
<ul>
|
||||
';
|
||||
foreach ($tabs as $name=>$value) {
|
||||
$subMenuOptions .= '
|
||||
<li class="menu-item '.$name.' '.($tab == $name ? ' active' : '').'">
|
||||
<a href="?view='.$view_.'&tab='.$name.'">
|
||||
<span class="menu-title">'.$value.'</span>
|
||||
</a>
|
||||
</li>'.PHP_EOL;
|
||||
}
|
||||
$subMenuOptions .= '
|
||||
</ul>
|
||||
</div>
|
||||
';
|
||||
|
||||
$result .= '
|
||||
<li id="getOptionsHTML" class="menu-item sub-menu '.($view == "options" ? ' open' : '').'">
|
||||
<a href="#<!--?view='.$view_.'&tab=system-->">
|
||||
<span class="menu-icon"><i class="material-icons">settings</i></span>
|
||||
<span class="menu-title">'.translate('Options').'</span>
|
||||
</a>
|
||||
' . $subMenuOptions . '
|
||||
</li>'.PHP_EOL;
|
||||
} else {
|
||||
$result .= '<li id="getOptionsHTML" class="nav-item"><a class="nav-link" href="?view=options">'.translate('Options').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Log menu item
|
||||
function getLogHTML() {
|
||||
function getLogHTML($forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('System') ) {
|
||||
if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) {
|
||||
$logstate = logState();
|
||||
$class = ($logstate == 'ok') ? 'text-success' : ($logstate == 'alert' ? 'text-warning' : (($logstate == 'alarm' ? 'text-danger' : '')));
|
||||
$result .= '<li id="getLogHTML" class="nav-item"><a class="nav-link '.$class.'" href="?view=log">'.translate('Log').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'log',
|
||||
$id = 'getLogHTML',
|
||||
$itemName = 'Log',
|
||||
$href = '?view=log',
|
||||
$icon = 'notification_important',
|
||||
$classNameForTag_A = $class,
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getLogHTML" class="nav-item"><a class="nav-link '.$class.'" href="?view=log">'.translate('Log').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,7 +1075,7 @@ function getLogIconHTML() {
|
||||
$logstate = logState();
|
||||
$class = ($logstate == 'ok') ? 'text-success' : ($logstate == 'alert' ? 'text-warning' : (($logstate == 'alarm' ? 'text-danger' : '')));
|
||||
$result .= '<li id="getLogIconHTML" class="nav-item">'.
|
||||
makeLink('?view=log', '<span class="mx-1 ' .$class. '"><i class="material-icons md-18" style="display: inline-block;">report</i>'.translate('Log').'</span>').
|
||||
makeLink('?view=log', '<span class="mx-1 ' .$class. '"><i class="material-icons md-18">report</i>'.translate('Log').'</span>').
|
||||
'</li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
@@ -756,65 +1084,126 @@ function getLogIconHTML() {
|
||||
}
|
||||
|
||||
// Returns the html representing the X10 Devices menu item
|
||||
function getDevicesHTML() {
|
||||
function getDevicesHTML($forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( ZM_OPT_X10 && canView('Devices') ) {
|
||||
$result .= '<li id="getDevicesHTML" class="nav-item"><a class="nav-link" href="?view=devices">Devices</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'devices',
|
||||
$id = 'getDevicesHTML',
|
||||
$itemName = 'Devices',
|
||||
$href = '?view=devices',
|
||||
$icon = 'devices_other',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getDevicesHTML" class="nav-item"><a class="nav-link" href="?view=devices">'.translate('Devices').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Groups menu item
|
||||
function getGroupsHTML($view) {
|
||||
function getGroupsHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
if ( !canView('Groups') ) return $result;
|
||||
|
||||
$class = $view == 'groups' ? ' selected' : '';
|
||||
$result .= '<li id="getGroupsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=groups">'. translate('Groups') .'</a></li>'.PHP_EOL;
|
||||
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'groups',
|
||||
$id = 'getGroupsHTML',
|
||||
$itemName = 'Groups',
|
||||
$href = '?view=groups',
|
||||
$icon = 'group',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getGroupsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=groups">'. translate('Groups') .'</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Filter menu item
|
||||
function getFilterHTML($view) {
|
||||
function getFilterHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
if ( !canView('Events') ) return $result;
|
||||
|
||||
$class = $view == 'filter' ? ' selected' : '';
|
||||
$result .= '<li id="getFilterHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=filter">'.translate('Filters').'</a></li>'.PHP_EOL;
|
||||
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'filter',
|
||||
$id = 'getFilterHTML',
|
||||
$itemName = 'Filters',
|
||||
$href = '?view=filter',
|
||||
$icon = 'filter_alt',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getFilterHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=filter">'.translate('Filters').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Cycle menu item
|
||||
function getCycleHTML($view) {
|
||||
function getCycleHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Stream') ) {
|
||||
$class = $view == 'cycle' ? ' selected' : '';
|
||||
$result .= '<li id="getCycleHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=watch&cycle=true">' .translate('Cycle'). '</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'watch',
|
||||
$id = 'getCycleHTML',
|
||||
$itemName = 'Cycle',
|
||||
$href = '?view=watch&cycle=true',
|
||||
//$icon = 'cyclone',
|
||||
$icon = 'repeat',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getCycleHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=watch&cycle=true">' .translate('Cycle'). '</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Montage menu item
|
||||
function getMontageHTML($view) {
|
||||
function getMontageHTML($view, $forLeftBar = false) {
|
||||
global $user;
|
||||
$result = '';
|
||||
|
||||
if (canView('Stream') and count($user->viewableMonitorIds())) {
|
||||
$class = $view == 'montage' ? ' selected' : '';
|
||||
$result .= '<li id="getMontageHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=montage">' .translate('Montage'). '</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'montage',
|
||||
$id = 'getMontageHTML',
|
||||
$itemName = 'Montage',
|
||||
$href = '?view=montage',
|
||||
$icon = 'live_tv',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getMontageHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=montage">' .translate('Montage'). '</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the MontageReview menu item
|
||||
function getMontageReviewHTML($view) {
|
||||
function getMontageReviewHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Events') ) {
|
||||
@@ -834,54 +1223,139 @@ function getMontageReviewHTML($view) {
|
||||
}
|
||||
$live = isset($montageReviewQuery) ? '&fit=1'.$montageReviewQuery.'&live=0' : '';
|
||||
$class = $view == 'montagereview' ? ' selected' : '';
|
||||
$result .= '<li id="getMontageReviewHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=montagereview' .$live. '">'.translate('MontageReview').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'montagereview',
|
||||
$id = 'getMontageReviewHTML',
|
||||
$itemName = 'MontageReview',
|
||||
$href = '?view=montagereview' .$live,
|
||||
$icon = 'movie',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getMontageReviewHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=montagereview' .$live. '">'.translate('MontageReview').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Montage menu item
|
||||
function getSnapshotsHTML($view) {
|
||||
function getSnapshotsHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if (defined('ZM_FEATURES_SNAPSHOTS') and ZM_FEATURES_SNAPSHOTS and canView('Snapshots')) {
|
||||
$class = $view == 'snapshots' ? ' selected' : '';
|
||||
$result .= '<li id="getSnapshotsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=snapshots">' .translate('Snapshots'). '</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'snapshots',
|
||||
$id = 'getSnapshotsHTML',
|
||||
$itemName = 'Snapshots',
|
||||
$href = '?view=snapshots',
|
||||
$icon = 'preview',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getSnapshotsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=snapshots">' .translate('Snapshots'). '</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function getReportsHTML($view) {
|
||||
// Returns the html representing the Events menu item
|
||||
function getEventsHTML($view, $forLeftBar = false) {
|
||||
global $user;
|
||||
$result = '';
|
||||
|
||||
if (canView('Events')) {
|
||||
$class = $view == 'events' ? ' selected' : '';
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'events',
|
||||
$id = 'getEventsHTML',
|
||||
$itemName = 'Events',
|
||||
$href = '?view=events',
|
||||
$icon = 'event',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getEventsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=events">' .translate('Events'). '</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function getReportsHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if (canView('Events')) {
|
||||
$class = ($view == 'reports' or $view == 'report') ? ' selected' : '';
|
||||
$result .= '<li id="getReportsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=reports">'.translate('Reports').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'reports',
|
||||
$id = 'getReportsHTML',
|
||||
$itemName = 'Reports',
|
||||
$href = '?view=reports',
|
||||
$icon = 'report',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getReportsHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=reports">'.translate('Reports').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Audit Events Report menu item
|
||||
function getRprtEvntAuditHTML($view) {
|
||||
function getRprtEvntAuditHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Events') ) {
|
||||
$class = $view == 'report_event_audit' ? ' selected' : '';
|
||||
$result .= '<li id="getRprtEvntAuditHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=report_event_audit">'.translate('ReportEventAudit').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'report_event_audit',
|
||||
$id = 'getRprtEvntAuditHTML',
|
||||
$itemName = 'ReportEventAudit',
|
||||
$href = '?view=report_event_audit',
|
||||
$icon = 'shield',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getRprtEvntAuditHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=report_event_audit">'.translate('ReportEventAudit').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Audit Events Report menu item
|
||||
function getMapHTML($view) {
|
||||
function getMapHTML($view, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if (defined('ZM_OPT_USE_GEOLOCATION') and ZM_OPT_USE_GEOLOCATION) {
|
||||
$class = $view == 'map' ? ' selected' : '';
|
||||
$result .= '<li id="getMapHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=map">'.translate('Map').'</a></li>'.PHP_EOL;
|
||||
if ($forLeftBar) {
|
||||
$result .= buildMenuItem(
|
||||
$viewItemName = 'map',
|
||||
$id = 'getMapHTML',
|
||||
$itemName = 'Map',
|
||||
$href = '?view=map',
|
||||
$icon = 'language',
|
||||
$classNameForTag_A = '',
|
||||
$subMenu = ''
|
||||
);
|
||||
} else {
|
||||
$result .= '<li id="getMapHTML" class="nav-item"><a class="nav-link'.$class.'" href="?view=map">'.translate('Map').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
@@ -909,13 +1383,13 @@ function getHeaderFlipHTML() {
|
||||
$result = '';
|
||||
|
||||
$header = ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down') ? 'down' : 'up';
|
||||
$result .= '<li id="getHeaderFlipHTML" class="nav-item dropdown"><a class="nav-link" href="#"><i id="flip" class="material-icons md-18" style="display: inline-block;">keyboard_arrow_' .$header. '</i></a></li>'.PHP_EOL;
|
||||
$result .= '<li id="getHeaderFlipHTML" class="nav-item dropdown"><a class="nav-link" href="#"><i id="flip" class="material-icons md-18">keyboard_arrow_' .$header. '</i></a></li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the logged in user name and avatar
|
||||
function getAccountCircleHTML($skin, $user=null) {
|
||||
function getAccountCircleHTML($skin, $user=null, $forLeftBar = false) {
|
||||
$result = '';
|
||||
|
||||
if ( ZM_OPT_USE_AUTH and $user ) {
|
||||
@@ -939,7 +1413,7 @@ function getStatusBtnHTML($status) {
|
||||
|
||||
if (ZM_SYSTEM_SHUTDOWN) {
|
||||
$result .= '<li class="shutdown">'.PHP_EOL;
|
||||
$result .= '<button id="shutdownButton" class="btn btn-default navbar-btn" data-on-click="getShutdownModal" data-toggle="tooltip" data-placement="top" title="' .translate('Shutdown'). '"><i class="material-icons md-18" style="display: inline-block;">power_settings_new</i></button>'.PHP_EOL;
|
||||
$result .= '<button id="shutdownButton" class="btn btn-default navbar-btn" data-on-click="getShutdownModal" data-toggle="tooltip" data-placement="top" title="' .translate('Shutdown'). '"><i class="material-icons md-18">power_settings_new</i></button>'.PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
@@ -1040,6 +1514,10 @@ function getCSRFinputHTML() {
|
||||
}
|
||||
|
||||
function xhtmlFooter() {
|
||||
global $useOldMenuView;
|
||||
if ($useOldMenuView !== true) {
|
||||
getSidebarBottomHTML();
|
||||
}
|
||||
global $css;
|
||||
global $cspNonce;
|
||||
global $view;
|
||||
@@ -1055,6 +1533,11 @@ function xhtmlFooter() {
|
||||
<script src="<?php echo cache_bust('js/ajaxQueue.js') ?>"></script>
|
||||
<script src="skins/<?php echo $skin; ?>/js/bootstrap-4.5.0.min.js"></script>
|
||||
<?php
|
||||
if (!$useOldMenuView) {
|
||||
echo output_script_if_exists(array('assets/pro-sidebar-template/dist/main.js'));
|
||||
echo output_script_if_exists(array('assets/mb.extruder/inc/mbExtruder.js'));
|
||||
echo output_script_if_exists(array('assets/swiped-events/dist/swiped-events.min.js'));
|
||||
}
|
||||
if ( $basename == 'montage' ) {
|
||||
echo output_script_if_exists(array('assets/gridstack/dist/gridstack-all.js'));
|
||||
echo output_script_if_exists(array('assets/jquery.panzoom/dist/jquery.panzoom.js'));
|
||||
|
||||
@@ -43,6 +43,13 @@ var expiredTap; //Time between touch screen clicks. Used to analyze double click
|
||||
var shifted = ctrled = alted = false;
|
||||
var mainContent = document.getElementById('content');
|
||||
|
||||
const useOldMenuView = !!getCookie('zmUseOldMenuView');
|
||||
const showExtruderPanelOnMouseHover = false;
|
||||
const NAVBAR_RELOAD = document.getElementById('reload'); // Top panel with statistics
|
||||
const BTN_COLLAPSE = document.getElementById('btn-collapse'); // Button to switch the menu view collapsed/expanded
|
||||
const SIDEBAR_MAIN = document.getElementById('sidebarMain'); // Left Sidebar with Menu
|
||||
const SIDEBAR_MAIN_EXTRUDER = document.getElementById('extruderLeft'); // Sliding extruder panel from the left Sidebar
|
||||
|
||||
function checkSize() {
|
||||
if ( 0 ) {
|
||||
if (window.outerHeight) {
|
||||
@@ -550,12 +557,43 @@ function submitTab(evt) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
function submitThisForm() {
|
||||
if ( ! this.form ) {
|
||||
// Called by 'data-on-change=submitThisForm' for Select and in Montage page when date/time changes
|
||||
function submitThisForm(param = null) {
|
||||
var form = null;
|
||||
var filter = null; // The filter that we previously moved to the left sidebar menu
|
||||
if (currentView == 'console' && !useOldMenuView) {
|
||||
// We get the form that we process
|
||||
form = document.querySelector('form[name="monitorForm"]');
|
||||
// We get a filter
|
||||
filter = document.querySelector('#fbpanel');
|
||||
} else if (currentView == 'montage' && !useOldMenuView) {
|
||||
form = document.querySelector('#filters_form');
|
||||
// Filter is inside the form.
|
||||
} else if (currentView == 'montagereview' && !useOldMenuView) {
|
||||
form = document.querySelector('#montagereview_form');
|
||||
filter = document.querySelector('#filterMontagereview');
|
||||
} else if (currentView == 'watch' && !useOldMenuView) {
|
||||
form = document.querySelector('#wrapperFilter form');
|
||||
} else {
|
||||
form = this.form;
|
||||
}
|
||||
|
||||
if ( ! form ) {
|
||||
console.log("No this.form. element with onchange is not in a form");
|
||||
return;
|
||||
}
|
||||
this.form.submit();
|
||||
if (filter && !useOldMenuView) {
|
||||
// Let's hide the old filter so that it doesn't appear during the transfer...
|
||||
filter.style.display = 'none';
|
||||
// We return the filter to its place in the form, since in the left side menu the filter should always be inside the form.
|
||||
form.prepend(filter);
|
||||
}
|
||||
if (param && typeof param === 'string') { //ON WATCH PAGE WHEN SELECTING A MONITOR, the object is transferred as PARAM!!!
|
||||
var uri = "?" + $j(form).serialize() + param;
|
||||
window.location = uri;
|
||||
} else {
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -687,6 +725,7 @@ function endOfResize(e) {
|
||||
//Only for scaleToFit
|
||||
changeScale();
|
||||
}
|
||||
isNavbarOverflown();
|
||||
}, 250);
|
||||
}
|
||||
window.onresize = endOfResize;
|
||||
@@ -1205,6 +1244,10 @@ function isMobile() {
|
||||
return result;
|
||||
}
|
||||
|
||||
function isTouchDevice() {
|
||||
return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
|
||||
}
|
||||
|
||||
function destroyChosen(selector = '') {
|
||||
if (typeof selector === 'string') {
|
||||
$j(selector + '.chosen').chosen('destroy');
|
||||
@@ -1432,18 +1475,359 @@ function canPlayCodec(filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Top bar with statistics
|
||||
* This function is necessary because
|
||||
* .dropdown-menu cannot extend beyond #reload container if #reload overflow == auto
|
||||
* overflow == auto for #reload is needed to scroll #reload on narrow screen.
|
||||
* Now on a wide screen we have a beautiful .dropdown-menu, on a narrow screen it is less beautiful.
|
||||
*/
|
||||
function isNavbarOverflown() {
|
||||
if (!NAVBAR_RELOAD) return; // For example, when you log in, nothing will happen...
|
||||
// If it doesn't fit, turn on overflow
|
||||
if (NAVBAR_RELOAD.scrollWidth > NAVBAR_RELOAD.clientWidth) {
|
||||
NAVBAR_RELOAD.style.overflowX = 'auto';
|
||||
document.querySelectorAll("#panel .dropdown-menu").forEach(function(el) {
|
||||
el.classList.add('overflown');
|
||||
});
|
||||
} else {
|
||||
NAVBAR_RELOAD.style.overflowX = 'visible';
|
||||
document.querySelectorAll("#panel .dropdown-menu").forEach(function(el) {
|
||||
el.classList.remove('overflown');
|
||||
});
|
||||
}
|
||||
|
||||
if (useOldMenuView) {
|
||||
if (window.innerWidth < 600) { // To support the old top menu
|
||||
document.getElementById('main-header-nav').appendChild(document.getElementById('blockUseOldMenuView'));
|
||||
} else {
|
||||
document.querySelector('#navbar-container .navbar-brand').appendChild(document.getElementById('blockUseOldMenuView'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function changeAttrTitle(collapsed = null) {
|
||||
if (!SIDEBAR_MAIN) return;
|
||||
if (collapsed === null) collapsed = SIDEBAR_MAIN.classList.contains('collapsed');
|
||||
// First level menu
|
||||
// Let's create (for collapsed, to make it clearer or if the title doesn't fit) or remove (for expanded, so as not to irritate) the "Title" attribute
|
||||
SIDEBAR_MAIN.querySelectorAll("nav>ul>li.menu-item>a").forEach(function(el) {
|
||||
const titleEl = el.querySelector("span.menu-title");
|
||||
if (collapsed || titleEl.scrollWidth > titleEl.clientWidth) {
|
||||
el.setAttribute('title', el.querySelector("span.menu-title").textContent);
|
||||
} else {
|
||||
el.setAttribute('title', '');
|
||||
}
|
||||
});
|
||||
|
||||
// For submenu we will add only if the title does not fit in the visible area in width...
|
||||
SIDEBAR_MAIN.querySelectorAll("nav>ul>li.menu-item.sub-menu .sub-menu-list>ul>li.menu-item a").forEach(function(el) {
|
||||
const titleEl = el.querySelector("span");
|
||||
if (titleEl.scrollWidth > titleEl.clientWidth) {
|
||||
el.setAttribute('title', el.querySelector("span.menu-title").textContent);
|
||||
} else {
|
||||
el.setAttribute('title', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* We create a retractable extruder block with filter settings (we move filters from the top panel) and a button in the left Sidebar menu */
|
||||
function insertControlModuleMenu() {
|
||||
var filter = null;
|
||||
if (currentView == 'console') {
|
||||
destroyChosen(); // It is required to be performed BEFORE receiving the object and only for those pages on which we transfer the filter
|
||||
filter = document.querySelector('#fbpanel');
|
||||
} else if (currentView == 'montage') {
|
||||
destroyChosen();
|
||||
filter = document.querySelector('#filters_form');
|
||||
} else if (currentView == 'montagereview') {
|
||||
destroyChosen();
|
||||
filter = document.createElement('div');
|
||||
filter.setAttribute("id", "filterMontagereview");
|
||||
|
||||
const filterOne = document.querySelector('#mfbpanel .controlHeader');
|
||||
const filterTwo = document.querySelector('#fieldsTable');
|
||||
filter.prepend(filterTwo);
|
||||
filter.prepend(filterOne);
|
||||
} else if (currentView == 'watch') {
|
||||
destroyChosen();
|
||||
filter = document.querySelector('.controlHeader form');
|
||||
} else if (currentView == 'report_event_audit') {
|
||||
destroyChosen();
|
||||
filter = document.querySelector('#content form');
|
||||
} else if (currentView == 'events') {
|
||||
destroyChosen();
|
||||
filter = document.querySelector('#fieldsTable');
|
||||
// We change the layout to remove the resulting void.
|
||||
const toolbar = document.querySelector('#toolbar');
|
||||
// The first div that is "col-sm-1"
|
||||
const divFirst = toolbar.querySelector('.col-sm-1');
|
||||
if (divFirst) {
|
||||
divFirst.classList.remove('col-sm-1');
|
||||
divFirst.classList.add('col-sm-4');
|
||||
}
|
||||
// The second div, which is "col-sm-9"
|
||||
const divSecond = toolbar.querySelector('.col-sm-9');
|
||||
if (divSecond) {
|
||||
divSecond.style.display = 'none';
|
||||
}
|
||||
// The third div, which is "col-sm-2"
|
||||
const divThird = toolbar.querySelector('.col-sm-2');
|
||||
if (divThird) {
|
||||
divThird.classList.remove('col-sm-2');
|
||||
divThird.classList.add('col-sm-8');
|
||||
}
|
||||
}
|
||||
|
||||
if (!filter) return;
|
||||
filter.classList.add('filter-block');
|
||||
|
||||
// Restore visibility. If the block was hidden
|
||||
filter.classList.remove('hidden-shift');
|
||||
filter.style.display = '';
|
||||
|
||||
//Create a button to open/hide the filter settings control
|
||||
var el = document.createElement('div');
|
||||
el.setAttribute("class", "menu-item");
|
||||
el.innerHTML = `
|
||||
<a href="#" class="text-success" title="Filter settings">
|
||||
<span class="bg-light menu-icon"><i class="material-icons">tune</i></span>
|
||||
<span class="menu-title">Filter settings</span>
|
||||
</a>
|
||||
`;
|
||||
|
||||
const menuControlModule = $j(document.querySelector('#menuControlModule'));
|
||||
const containerExtruderLeft = $j(document.querySelector('#contextExtruderLeft'));
|
||||
menuControlModule.prepend(el); // Menu line
|
||||
|
||||
// Let's create a wrapper for the filter, since the filter can start with a <span> tag or something similar.
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.setAttribute("id", "wrapperFilter");
|
||||
// Let's add a filter to wrapper
|
||||
wrapper.prepend(filter);
|
||||
// We will create a button to close extruder panel, which is relevant for narrow screens
|
||||
var btnClose = document.createElement('span');
|
||||
btnClose.setAttribute("class", "btn");
|
||||
btnClose.setAttribute("id", "wrapperBtnCloseExtruder");
|
||||
//btnClose.style.position = "absolute";
|
||||
//btnClose.style.top = "0";
|
||||
//btnClose.style.right = "0";
|
||||
btnClose.innerHTML = `<i id="btnCloseExtruder" class="material-icons">close</i>`;
|
||||
wrapper.prepend(btnClose);
|
||||
// Let's place the filter itself
|
||||
containerExtruderLeft.replaceWith(wrapper);
|
||||
|
||||
$j(SIDEBAR_MAIN_EXTRUDER).buildMbExtruder({
|
||||
attachToParentSide: "right", // Bind to right side of parent
|
||||
bindToButtonByHeight: document.querySelector('#menuControlModule'), // Bind vertical position to button. Relevant when the button moves vertically, so that the extruder follows it.
|
||||
position: "left",
|
||||
selectorResponsiveBlock: '.filter-block',
|
||||
extruderParentElement: document.getElementById('sidebarMain'),
|
||||
noFlap: true,
|
||||
width: 400,
|
||||
topBlock: 300,
|
||||
topFlap: 100,
|
||||
extruderOpacity: .9,
|
||||
//zIndex: 100,
|
||||
onExtOpen: function() {},
|
||||
onExtContentLoad: function() {},
|
||||
onExtClose: function() {}
|
||||
});
|
||||
|
||||
// Assign to Show/hide button
|
||||
menuControlModule.on("click", function() {
|
||||
if (!SIDEBAR_MAIN_EXTRUDER.classList.contains('isOpened')) {
|
||||
$j(SIDEBAR_MAIN_EXTRUDER).openMbExtruder();
|
||||
} else {
|
||||
$j(SIDEBAR_MAIN_EXTRUDER).closeMbExtruder();
|
||||
}
|
||||
});
|
||||
|
||||
// NECESSARY BECAUSE DOM HAS BEEN REBUILDED!
|
||||
dataOnClickThis();
|
||||
dataOnClick();
|
||||
dataOnClickTrue();
|
||||
dataOnChangeThis();
|
||||
dataOnChange();
|
||||
dataOnInput();
|
||||
dataOnInputThis();
|
||||
applyChosen();
|
||||
initDatepicker();
|
||||
if (getCookie('zmVisibleMbExtruder')) {
|
||||
// The extruder panel was open when the previous page was closed. Perhaps the filter settings were changed before the previous page was closed.
|
||||
$j(SIDEBAR_MAIN_EXTRUDER).openMbExtruder();
|
||||
}
|
||||
|
||||
/* Need to change overflow for extruder sidebar
|
||||
* If the "chosen" drop-down list fits vertically into the browser window, then overflow = 'visible' is for beauty.
|
||||
* That is, the list will be on top of the block, and the block will not increase in height. Otherwise, we will set overflow = 'auto' for the panel so that the "chosen" drop-down list is fully accessible.
|
||||
* We listen to ".chosen-container" for ".chosen-container-active" to be added or removed.
|
||||
*/
|
||||
document.querySelectorAll(".chosen-container").forEach(function(el) {
|
||||
const ob = new MutationObserver(function() {
|
||||
const parent = SIDEBAR_MAIN_EXTRUDER.querySelector('.filter-block');
|
||||
if (!parent) return; // Page closing moment
|
||||
if (el.classList.contains("chosen-container-active")) {
|
||||
const chosenDropBlock = el.querySelector('.chosen-drop');
|
||||
//const [leftDropBlock, topDropBlock] = findPos(chosenDropBlock); // Eslint complains about not using leftDropBlock
|
||||
const topDropBlock = findPos(chosenDropBlock)[1];
|
||||
|
||||
if (chosenDropBlock.clientHeight + topDropBlock > window.innerHeight ) { // There is not enough space at the bottom
|
||||
parent.style.overflow = 'auto';
|
||||
} else {
|
||||
parent.style.overflow = 'visible';
|
||||
}
|
||||
} else {
|
||||
//parent.style.overflow = 'visible';
|
||||
}
|
||||
});
|
||||
ob.observe(el, {
|
||||
attributes: true,
|
||||
attributeFilter: ["class"]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Get the position of an element. Relevant for nested position == fixed&absolute
|
||||
function findPos(obj, foundScrollLeft, foundScrollTop) {
|
||||
var curleft = 0;
|
||||
var curtop = 0;
|
||||
if (obj.offsetLeft) curleft += parseInt(obj.offsetLeft);
|
||||
if (obj.offsetTop) curtop += parseInt(obj.offsetTop);
|
||||
if (obj.scrollTop && obj.scrollTop > 0) {
|
||||
curtop -= parseInt(obj.scrollTop);
|
||||
foundScrollTop = true;
|
||||
}
|
||||
if (obj.scrollLeft && obj.scrollLeft > 0) {
|
||||
curleft -= parseInt(obj.scrollLeft);
|
||||
foundScrollLeft = true;
|
||||
}
|
||||
if (obj.offsetParent) {
|
||||
var pos = findPos(obj.offsetParent, foundScrollLeft, foundScrollTop);
|
||||
curleft += pos[0];
|
||||
curtop += pos[1];
|
||||
} else if (obj.ownerDocument) {
|
||||
var thewindow = obj.ownerDocument.defaultView;
|
||||
if (!thewindow && obj.ownerDocument.parentWindow) thewindow = obj.ownerDocument.parentWindow;
|
||||
if (thewindow) {
|
||||
if (!foundScrollTop && thewindow.scrollY && thewindow.scrollY > 0) curtop -= parseInt(thewindow.scrollY);
|
||||
if (!foundScrollLeft && thewindow.scrollX && thewindow.scrollX > 0) curleft -= parseInt(thewindow.scrollX);
|
||||
if (thewindow.frameElement) {
|
||||
var pos = findPos(thewindow.frameElement);
|
||||
curleft += pos[0];
|
||||
curtop += pos[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [curleft, curtop];
|
||||
}
|
||||
|
||||
/* Handling <input> change */
|
||||
function handleChangeInputTag(evt) {
|
||||
// Managing availability of channel stream selection
|
||||
manageRTSP2WebChannelStream();
|
||||
}
|
||||
|
||||
/* Handling a mouse click */
|
||||
function handleClickGeneral(evt) {
|
||||
const target = evt.target;
|
||||
if (!useOldMenuView) {
|
||||
if (SIDEBAR_MAIN_EXTRUDER.contains(target)) {
|
||||
// Click on any element inside the extruder panel from the Sidebar
|
||||
} else {
|
||||
// Click outside the extruder panel
|
||||
if (!SIDEBAR_MAIN.contains(target) &&
|
||||
//"datepicker" changes the DOM very quickly when the month changes. Closest does not have time to go through all the parents, but only manages to get to the first parent. It is necessary to additionally analyze '.ui-datepicker-prev' and '.ui-datepicker-next'
|
||||
!target.closest('.ui-datepicker') &&
|
||||
!target.closest('.ui-datepicker-prev') &&
|
||||
!target.closest('.ui-datepicker-next') &&
|
||||
!target.matches('button[name="deleteBtn"]')) { // Multi select clear button
|
||||
// Click outside the extruder panel Sidebar (except clicking on "datepicker"). Close the extruder panel
|
||||
closeMbExtruder();
|
||||
}
|
||||
}
|
||||
// Collapse or expand the menu.
|
||||
if (BTN_COLLAPSE && BTN_COLLAPSE.contains(target)) {
|
||||
setTimeout(function() {
|
||||
// Call only after finishing expanding or collapsing. Otherwise the dimensions will be incorrect.
|
||||
const collapsed = SIDEBAR_MAIN.classList.contains('collapsed');
|
||||
setCookie('zmSidebarMainCollapse', collapsed);
|
||||
changeAttrTitle(collapsed);
|
||||
}, 500);
|
||||
}
|
||||
// Extruder panel close button with filters. Appears on narrow screens
|
||||
if ('btnCloseExtruder' == target.id && SIDEBAR_MAIN_EXTRUDER) {
|
||||
closeMbExtruder();
|
||||
}
|
||||
}
|
||||
// Toggle between using the old or new menu
|
||||
if (document.getElementById('useOldMenuView') == target) {
|
||||
setCookie('zmUseOldMenuView', target.checked);
|
||||
refreshWindow();
|
||||
}
|
||||
|
||||
// Click on <input> to open the "datepicker" window
|
||||
// For ui-datepicker we track the change of style "display" and to front
|
||||
// This is necessary because some blocks, such as "extruder" always push themselves to the foreground. At the same time, "datepicker" should ALWAYS be displayed on top of all blocks. "z-index: XXX !important will not help in this case!
|
||||
if (target.classList.contains('hasDatepicker')) {
|
||||
const datepicker = document.getElementById('ui-datepicker-div');
|
||||
if (datepicker) {
|
||||
datepicker.style.removeProperty('z-index'); // Without this, problems are possible.
|
||||
datepicker.style.setProperty('z-index', '1000000', 'important'); //Now "datepicker" will always be displayed on top of other blocks.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle any action on the touch screen */
|
||||
function handleTouchActionGeneral(action, evt) {
|
||||
//https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
|
||||
if (action == 'touchstart') {
|
||||
managePanZoomButton(evt);
|
||||
} else if (action == 'touchend') {
|
||||
} else if (action == 'touchcancel') {
|
||||
} else if (action == 'touchmove') {
|
||||
//evt.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/* Processing any key press*/
|
||||
function handleKeydownGeneral(evt) {
|
||||
const target = evt.target;
|
||||
const key = evt.key;
|
||||
// Controls pressing "Enter" inside the sliding panel from Sidebar. Used to submit the form to the Console page.
|
||||
if (!useOldMenuView && key == 'Enter') {
|
||||
if (SIDEBAR_MAIN_EXTRUDER.contains(target)) {
|
||||
submitThisForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseover(evt) {
|
||||
manageVisibilityVideoPlayerControlPanel(evt, 'show');
|
||||
if (!useOldMenuView) {
|
||||
manageVisibilitySidebarExtruderPanel(evt, 'show');
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseout(evt) {
|
||||
manageVisibilityVideoPlayerControlPanel(evt, 'hide');
|
||||
if (!useOldMenuView) {
|
||||
manageVisibilitySidebarExtruderPanel(evt, 'hide');
|
||||
}
|
||||
}
|
||||
|
||||
function manageVisibilitySidebarExtruderPanel(evt, action) {
|
||||
if (!showExtruderPanelOnMouseHover) return;
|
||||
if (evt.target.closest('#menuControlModule') &&
|
||||
// Avoid false positives when moving mouse inside '#menuControlModule'
|
||||
(evt.relatedTarget && evt.relatedTarget.closest('#menuControlModule') != evt.target.closest('#menuControlModule'))) {
|
||||
if (action == 'show') {
|
||||
$j(SIDEBAR_MAIN_EXTRUDER).openMbExtruder();
|
||||
} else if (action == 'hide') {
|
||||
// We don't do anything yet, because now the block closes either when you click on the button or anywhere on the page
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function manageVisibilityVideoPlayerControlPanel(evt, action) {
|
||||
@@ -1466,16 +1850,30 @@ function manageVisibilityVideoPlayerControlPanel(evt, action) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle any action on the touch screen */
|
||||
function handleTouchActionGeneral(action, evt) {
|
||||
//https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
|
||||
if (action == 'touchstart') {
|
||||
managePanZoomButton(evt);
|
||||
} else if (action == 'touchend') {
|
||||
} else if (action == 'touchcancel') {
|
||||
} else if (action == 'touchmove') {
|
||||
//evt.preventDefault();
|
||||
function initDatepicker() {
|
||||
if (currentView == 'events') {
|
||||
initDatepickerEventsPage();
|
||||
} else if (currentView == 'montagereview') {
|
||||
initDatepickerMontageReviewPage();
|
||||
} else if (currentView == 'report_event_audit') {
|
||||
initDatepickerReportEventAuditPage();
|
||||
}
|
||||
|
||||
// When hiding the "datepicker" you need to clear the 'z-index' property so that it does not affect other elements
|
||||
document.querySelectorAll(".ui-datepicker").forEach(function(el) {
|
||||
const ob = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.attributeName === 'style' && mutation.target.style.display === 'none' && mutation.target.style.zIndex) {
|
||||
console.log(">>zIndex>", mutation.target.style.zIndex);
|
||||
mutation.target.style.removeProperty('z-index');
|
||||
}
|
||||
});
|
||||
});
|
||||
ob.observe(el, {
|
||||
attributes: true,
|
||||
attributeFilter: ["style"]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function managePanZoomButton(evt) {
|
||||
@@ -1490,6 +1888,7 @@ function managePanZoomButton(evt) {
|
||||
} else {
|
||||
$j('#button_zoom' + stringToNumber(targetId)).removeClass('hidden');
|
||||
}
|
||||
if (!('getAttribute' in evt.currentTarget)) return; // Touchscreen tap on '.imageFeed' does not have 'currentTarget'
|
||||
//evt.preventDefault();
|
||||
// We are looking for an object with an ID, because there may be another element in the button.
|
||||
const obj = targetId ? evt.target : evt.target.parentElement;
|
||||
@@ -1533,13 +1932,90 @@ function managePanZoomButton(evt) {
|
||||
}
|
||||
}
|
||||
|
||||
function closeMbExtruder(updateCookie = false) {
|
||||
if (!SIDEBAR_MAIN_EXTRUDER) return;
|
||||
if (updateCookie) {
|
||||
// We will save the panel visibility in cookies so that we can restore the state after opening a new page.
|
||||
// If the panel was open, it means that the filter was most likely adjusted.
|
||||
// It is probably worth analyzing whether a new page will be opened or the old one but with different parameters.
|
||||
setCookie('zmVisibleMbExtruder', !!SIDEBAR_MAIN_EXTRUDER.classList.contains('isOpened'));
|
||||
}
|
||||
$j(SIDEBAR_MAIN_EXTRUDER).closeMbExtruder();
|
||||
}
|
||||
|
||||
/*
|
||||
* The call is configured in \www\skins\classic\views\_monitor_filters.php
|
||||
* If many options were selected in the filter, then deleting them one by one takes a long time; it is easier to delete everything with one button.
|
||||
*/
|
||||
function resetSelectElement(el) {
|
||||
console.log("clearSelectMultiply_el=>", el);
|
||||
const selectElement = document.querySelector('select[name="'+el.getAttribute('data-select-target')+'"]');
|
||||
if (!selectElement) return;
|
||||
Array.from(selectElement.options).forEach((option) => {
|
||||
option.selected = false;
|
||||
});
|
||||
applyChosen(selectElement);
|
||||
|
||||
if (currentView == 'events') {
|
||||
filterEvents(clickedElement = selectElement);
|
||||
} else {
|
||||
submitThisForm();
|
||||
}
|
||||
}
|
||||
|
||||
function initPageGeneral() {
|
||||
$j(document).on('keyup.global keydown.global', function(e) {
|
||||
$j(document).on('keyup.global keydown.global', function handleKey(e) {
|
||||
shifted = e.shiftKey ? e.shiftKey : e.shift;
|
||||
ctrled = e.ctrlKey;
|
||||
alted = e.altKey;
|
||||
});
|
||||
|
||||
if (!useOldMenuView) {
|
||||
if ((!isTouchDevice() || !isMobile()) && NAVBAR_RELOAD) {
|
||||
// Increase the width of the scrollbar for NON-mobile or NON-touch devices
|
||||
NAVBAR_RELOAD.classList.add('high-scroll-bar');
|
||||
}
|
||||
changeAttrTitle();
|
||||
setTimeout(function() {
|
||||
// It takes time for all DOM actions to complete, especially with regard to block visibility.
|
||||
insertControlModuleMenu();
|
||||
isNavbarOverflown();
|
||||
}, 200);
|
||||
|
||||
// Swipe support, configurable via "data-swipe" in \skins\classic\includes\functions.php
|
||||
document.addEventListener('swiped', function addListenerGlobalSwiped(e) {
|
||||
//console.log(e.detail); // see event data below
|
||||
if (e.detail.dir == 'right') {
|
||||
if (e.detail.xStart < 80) {
|
||||
// SideBar Management
|
||||
if (SIDEBAR_MAIN.classList.contains('toggled')) { // The menu is already visible, but you can expand it wider
|
||||
SIDEBAR_MAIN.classList.remove('collapsed');
|
||||
} else {
|
||||
SIDEBAR_MAIN.classList.add('toggled');
|
||||
}
|
||||
}
|
||||
} else if (e.detail.dir == 'left') {
|
||||
if ((e.detail.xStart < 80) || ((e.detail.xStart < 250) && (!SIDEBAR_MAIN.classList.contains('collapsed') && SIDEBAR_MAIN.classList.contains('toggled')))) {
|
||||
// SideBar Management
|
||||
if (!SIDEBAR_MAIN.classList.contains('collapsed') && SIDEBAR_MAIN.classList.contains('toggled')) { // Fully expanded
|
||||
SIDEBAR_MAIN.classList.add('collapsed');
|
||||
} else {
|
||||
SIDEBAR_MAIN.classList.remove('toggled');
|
||||
}
|
||||
}
|
||||
} else if (e.detail.dir == 'down') {
|
||||
} else if (e.detail.dir == 'up') {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var observerNavbarReload = new window.ResizeObserver((entries) => {
|
||||
endOfResize();
|
||||
});
|
||||
if (NAVBAR_RELOAD) {
|
||||
observerNavbarReload.observe(NAVBAR_RELOAD);
|
||||
}
|
||||
|
||||
if (['montage', 'watch', 'devices', 'reports', 'monitorpreset', 'monitorprobe', 'onvifprobe', 'timeline'].includes(currentView)) {
|
||||
mainContent = document.getElementById('page');
|
||||
} else if (currentView == 'options') {
|
||||
@@ -1550,20 +2026,26 @@ function initPageGeneral() {
|
||||
/* Assigning global handlers!
|
||||
** IMPORTANT! It will not be possible to remove assigned handlers using the removeEventListener method, since the functions are anonymous
|
||||
*/
|
||||
document.body.addEventListener('input', function(event) {
|
||||
document.body.addEventListener('input', function addListenerGlobalInputTag(event) {
|
||||
handleChangeInputTag(event);
|
||||
});
|
||||
document.body.addEventListener('click', function addListenerGlobalClick(event) {
|
||||
handleClickGeneral(event);
|
||||
});
|
||||
document.body.addEventListener('keydown', function addListenerGlobalKeydown(event) {
|
||||
handleKeydownGeneral(event);
|
||||
});
|
||||
|
||||
document.body.addEventListener('mouseover', function(event) {
|
||||
document.body.addEventListener('mouseover', function addListenerGlobalMouseover(event) {
|
||||
handleMouseover(event);
|
||||
});
|
||||
document.body.addEventListener('mouseout', function(event) {
|
||||
document.body.addEventListener('mouseout', function addListenerGlobalMouseout(event) {
|
||||
handleMouseout(event);
|
||||
});
|
||||
|
||||
// Support for touch devices.
|
||||
['touchstart', 'touchend', 'touchcancel', 'touchmove'].forEach(function(action) {
|
||||
document.addEventListener(action, function(event) {
|
||||
document.addEventListener(action, function addListenerGlobalTouchAction(event) {
|
||||
handleTouchActionGeneral(action, event);
|
||||
}, {passive: false}); // false - to avoid an error "Unable to preventDefault inside passive event listener due to target being treated as passive."
|
||||
});
|
||||
@@ -1588,11 +2070,10 @@ function initPageGeneral() {
|
||||
|
||||
window.addEventListener('beforeunload', function addListenerGlobalBeforeunload(event) {
|
||||
//event.preventDefault();
|
||||
/*
|
||||
if (!useOldMenuView) {
|
||||
closeMbExtruder(updateCookie = true);
|
||||
}
|
||||
*/
|
||||
|
||||
if (mainContentJ) {
|
||||
if (mainContentJ.css('display') == 'flex') {
|
||||
// If flex-grow is set to a value > 0 then "height" will be ignored!
|
||||
|
||||
@@ -31,10 +31,26 @@ function addFilterSelect($name, $options) {
|
||||
)
|
||||
);
|
||||
$html .= '</span>';
|
||||
$html .= addButtonResetForFilterSelect($name.'[]');
|
||||
$html .= '</span>'.PHP_EOL;
|
||||
return $html;
|
||||
}
|
||||
|
||||
function addButtonResetForFilterSelect($nameSelect) {
|
||||
if (isset($_COOKIE['zmUseOldMenuView']) and $_COOKIE["zmUseOldMenuView"] === 'true') {
|
||||
$html = '';
|
||||
} else {
|
||||
$html = PHP_EOL . '
|
||||
<span class="btn-term-remove-all">
|
||||
<button type="button" name="deleteBtn" data-on-click-this="resetSelectElement" data-select-target="'.$nameSelect.'">
|
||||
<i class="material-icons">clear</i>
|
||||
<span class="text"></span>
|
||||
</button>
|
||||
</span>' . PHP_EOL;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
function buildMonitorsFilters() {
|
||||
global $user, $Servers;
|
||||
require_once('includes/Monitor.php');
|
||||
@@ -87,6 +103,7 @@ function buildMonitorsFilters() {
|
||||
$html .= ZM\Group::get_group_dropdown();
|
||||
$groupSql = ZM\Group::get_group_sql($group_id);
|
||||
$html .= '</span>';
|
||||
$html .= addButtonResetForFilterSelect('GroupId[]');
|
||||
$html .= '</span>';
|
||||
}
|
||||
}
|
||||
@@ -141,6 +158,7 @@ function buildMonitorsFilters() {
|
||||
)
|
||||
);
|
||||
$html .= '</span>';
|
||||
$html .= addButtonResetForFilterSelect('ServerId[]');
|
||||
$html .= '</span>';
|
||||
} # end if have Servers
|
||||
|
||||
@@ -156,6 +174,7 @@ function buildMonitorsFilters() {
|
||||
'data-placeholder'=>'All',
|
||||
) );
|
||||
$html .= '</span>';
|
||||
$html .= addButtonResetForFilterSelect('StorageId[]');
|
||||
$html .= '</span>';
|
||||
} # end if have Storage Areas
|
||||
|
||||
@@ -176,6 +195,7 @@ function buildMonitorsFilters() {
|
||||
'data-placeholder'=>'All'
|
||||
) );
|
||||
$html .= '</span>';
|
||||
$html .= addButtonResetForFilterSelect('Status[]');
|
||||
$html .= '</span>';
|
||||
|
||||
$html .= '<span class="term SourceFilter"><label>'.translate('Source').'</label>';
|
||||
@@ -284,6 +304,7 @@ function buildMonitorsFilters() {
|
||||
# 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 .= addButtonResetForFilterSelect('MonitorId[]');
|
||||
$html .= '</span>';
|
||||
$html .= '</div>';
|
||||
|
||||
|
||||
@@ -513,6 +513,23 @@ function initPage() {
|
||||
table.find('tr td:nth-child(' + (thumb_ndx+1) + ')').addClass('colThumbnail');
|
||||
});
|
||||
|
||||
if (useOldMenuView) {
|
||||
// If new menu is used, then Datepicker initialization occurs in main "skin.js"
|
||||
// Reinitialization is not allowed because the 'Destroy' method is missing.
|
||||
initDatepickerEventsPage();
|
||||
}
|
||||
|
||||
window.onpageshow = function(evt) {
|
||||
console.log('Refreshing table');
|
||||
table.bootstrapTable('refresh');
|
||||
};
|
||||
|
||||
table.bootstrapTable('resetSearch');
|
||||
// The table is initially given a hidden style, so now that we are done rendering, show it
|
||||
table.show();
|
||||
}
|
||||
|
||||
function initDatepickerEventsPage() {
|
||||
$j('#fieldsTable input, #fieldsTable select').each(function(index) {
|
||||
const el = $j(this);
|
||||
if (el.hasClass('datetimepicker')) {
|
||||
@@ -523,15 +540,6 @@ function initPage() {
|
||||
el.on('change', filterEvents);
|
||||
}
|
||||
});
|
||||
|
||||
window.onpageshow = function(evt) {
|
||||
console.log('Refreshing table');
|
||||
table.bootstrapTable('refresh');
|
||||
};
|
||||
|
||||
table.bootstrapTable('resetSearch');
|
||||
// The table is initially given a hidden style, so now that we are done rendering, show it
|
||||
table.show();
|
||||
}
|
||||
|
||||
function filterEvents(clickedElement) {
|
||||
|
||||
@@ -1257,6 +1257,15 @@ function initPage() {
|
||||
$j('#archive_status').bind('change', function() {
|
||||
this.form.submit();
|
||||
});
|
||||
|
||||
if (useOldMenuView) {
|
||||
// If new menu is used, then Datepicker initialization occurs in main "skin.js"
|
||||
// Reinitialization is not allowed because the 'Destroy' method is missing.
|
||||
initDatepickerMontageReviewPage();
|
||||
}
|
||||
}
|
||||
|
||||
function initDatepickerMontageReviewPage() {
|
||||
$j('#fieldsTable input, #fieldsTable select').each(function(index) {
|
||||
const el = $j(this);
|
||||
if (el.hasClass('datetimepicker')) {
|
||||
|
||||
@@ -21,7 +21,7 @@ function datetime_change(newDate, oldData) {
|
||||
}
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
function initDatepickerReportEventAuditPage() {
|
||||
$j('#minTime').datetimepicker({
|
||||
timeFormat: "HH:mm:ss",
|
||||
dateFormat: "yy-mm-dd",
|
||||
@@ -40,5 +40,13 @@ function initPage() {
|
||||
});
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
if (useOldMenuView) {
|
||||
// If new menu is used, then Datepicker initialization occurs in main "skin.js"
|
||||
// Reinitialization is not allowed because the 'Destroy' method is missing.
|
||||
initDatepickerReportEventAuditPage();
|
||||
}
|
||||
}
|
||||
|
||||
// Kick everything off
|
||||
window.addEventListener( 'DOMContentLoaded', initPage );
|
||||
|
||||
Reference in New Issue
Block a user