var _sg={
which:'',
doneSetup:false,
maskPicker0:null,
maskPicker1:null,
maskPicker2:null,
maskPicker3:null,
tickTimer:null,
updateTimer:null,
devListTimer:null,
camStatusTimer:null,
warningIconTimer:null,
formData:'',
updateButtonName:'',
updateVersion:0,
scriptCount:0,
whichPanelMask:0,
camMenu:null,
audioContext:null,
popupTrigger:'',
};
const kTriggers=['TriggerMotion','TriggerArrives','TriggerDeparts','TriggerAudio','TriggerCamP1','TriggerCamP2','TriggerCamPir','TriggerCamMd','TriggerHome'];
const kFormats=['JPEG HTTP','JPEG RTSP','JPEG RTSP-over-HTTP','MPEG-4 HTTP','MPEG-4 RTSP','MPEG-4 RTSP-over-HTTP','H.265 RTSP','H.264 RTSP','H.264 RTSP-over-HTTP','HTTP','RTSP','RTSP-over-HTTP','MxPEG HTTP','RTSP UDP','H.265 RTSP-over-HTTP','H.264 HTTP','H.265 HTTP'];
const kZeroBased=(1<<0);
const kSize=(1<<0);
const kRate=(1<<1);
const kQuality=(1<<2);
const kAudio=(1<<5);
const kV5Reversion=55555555;
const kVLatestBeta=66666666;
const kDeviceTypeLocal=0;
const kDeviceTypeNetwork=1;
const kDeviceTypeSimulated=3;
const kDeviceTypeScreen=4;
const kDeviceTypePush=5;
const kUploadTypeFtp=0;
const kUploadTypeFtps=1;
const kUploadTypeSftp=2;
const kUploadTypeS3=3;
const kUploadTypeLocal=4;
const kProfileSS=2;
const kProfileManual=3;
const kProfileOnvif=302;
function SetLoad(){
const scripts=['CamSorter','AccountPicker','FolderPicker','SchedulePicker','SchedulePresetPicker','MaskPicker','MultiSelectDiv','tracking'];
if(_sg.scriptCount){
SetDoLoad();
}else{
for(let name of scripts){
LoadScript(name,function(){
if(++_sg.scriptCount==scripts.length)SetDoLoad();
});
}
}
}
function SetDoLoad(){
const sidebar=document.getElementById('setSidebar');
const content=document.getElementById('setContent');
sidebar.style.display='flex';
content.style.display='block';
if(!_sg.doneSetup){
_sg.camMenu=new MultiSelectDiv(document.getElementById('setCamMenu'),SgCamSelectionChanged,SgCamRename);
for(let i=0;i<_cams.length;i++)_sg.camMenu.addOption(_cams[i].name,_cams[i].num);
if(getURLParameter('cameraNum')&& parseInt(getURLParameter('cameraNum'))>-1)_sg.camMenu.selectValue(parseInt(getURLParameter('cameraNum')));
if(_sg.camMenu.selectedValue()==='')_sg.camMenu.selectIndex(0);
_sg.doneSetup=true;
}
if(_sg.pendingCam!==undefined){
_sg.camMenu.selectValue(_sg.pendingCam);
SetRadioGroupValue('setTab','cameras');
_sg.pendingCam=undefined;
_sg.doneSetup=false;
}
if(allCookies.getItem('sgWhich')!=null)SetRadioGroupValue('setTab',allCookies.getItem('sgWhich'));
SgFetchPage();
SgGetDeviceList();
document.addEventListener('click',SgCloseTriggerPopup);
_sg.devListTimer=setInterval(SgGetDeviceList,60000);
_sg.warningIconTimer=setInterval(SgSetWarningIcons,2000);
if(_isSettingsWindow){
document.addEventListener('contextmenu',function(event){
if(event.target.tagName!=='INPUT'){
event.preventDefault();
}
});
}
}
function SgUnload(){
const sidebar=document.getElementById('setSidebar');
const content=document.getElementById('setContent');
sidebar.style.display='none';
content.style.display='none';
if(_sg.tickTimer){clearTimeout(_sg.tickTimer);_sg.tickTimer=null;}
if(_sg.devListTimer){clearInterval(_sg.devListTimer);_sg.devListTimer=null;}
if(_sg.warningIconTimer){clearInterval(_sg.warningIconTimer);_sg.warningIconTimer=null;}
if(_sg.updateTimer){clearTimeout(_sg.updateTimer);_sg.updateTimer=null;}
if(_sg.camStatusTimer){clearTimeout(_sg.camStatusTimer);_sg.camStatusTimer=null;}
document.removeEventListener('click',SgCloseTriggerPopup);
_sg.audioContext=null;
_sg.maskPicker0=null;
_sg.maskPicker1=null;
_sg.maskPicker2=null;
_sg.maskPicker3=null;
_sg.formData='';
_sg.which='';
}
function SgSelectedSection(){
var ele=document.getElementsByName('setTab');
for(let i=0;i<ele.length;i++)if(ele[i].checked)return ele[i].value;
return null;
}
function SgFetchPage(event,addParams,dontAskSave){
if(_sg.tickTimer){clearTimeout(_sg.tickTimer);_sg.tickTimer=null;}
let which=SgSelectedSection();
if(event && event.target && event.target.name==='setTab' && which===_sg.which)return;
let variant='',params='';
if(!which){
document.getElementById('setTabGeneral').checked=true;
which='general';
}
allCookies.setItem('sgWhich',which,600);
if(which=='cameras'){
let selectedCount=_sg.camMenu.selectedCount();
if(selectedCount>1){
variant='-multi';
}else{
params='cameraNum='+_sg.camMenu.selectedValue();
}
}
let path='settings-'+which+variant+'?'+params+(addParams?'&'+addParams:'')+((event && event.altKey)?'&alt=1':'');
if(_sg.which!='license' && dontAskSave!=true && _sg.formData && _sg.formData!=SgCurrentFormData()){
let alert=new Alert(Loc('save_changes'));
alert.addButton(Loc('Save'),async function(){
await SgSave();
SgDoFetchPage(which,path);
});
alert.addButton(Loc("Don't Save"),function(){
SgDoFetchPage(which,path);
});
}else{
SgDoFetchPage(which,path);
}
}
async function SgDoFetchPage(which,path){
let html=null;
try{
let result=await fetch(path,{credentials:'same-origin'});
if(!result.ok)throw new Error(`HTTP error ${result.status}`);
html=await result.text();
}catch(error){
document.getElementById('setContent').innerHTML=Loc('There was an error fetching this content')+'<br>'+error;
_sg.formData='';
return;
}
document.getElementById('setContent').innerHTML=html;
InitNumericInputs();
FixRangeElements();
FixTimeElements();
_sg.which=which;
_sg.maskPicker0=null;
_sg.maskPicker1=null;
_sg.maskPicker2=null;
_sg.maskPicker3=null;
if(_oemId==3){
if(document.getElementById('updateNotifyTr'))document.getElementById('updateNotifyTr').remove();
if(document.getElementById('ddnsTr'))document.getElementById('ddnsTr').remove();
if(document.getElementById('downtimeTr'))document.getElementById('downtimeTr').remove();
}
if(which=='cameras'){
let selectedCount=_sg.camMenu.selectedCount();
let isMulti=document.getElementById('setForm').action.endsWith('-multi');
document.getElementById('camDeleteButton').disabled=selectedCount?false:true;
document.getElementById('camGearButton').disabled=false;
if(!OSMeetsRequired("10.15")&& document.getElementById('aiMdOption')){
document.getElementById('aiMdOption').disabled=true;
document.getElementById('aiMdOption').innerHTML+=' '+Loc('(macOS 10.15 or later required)');
}
if(selectedCount){
if(isMulti){
elementNamed('cameras').value=_sg.camMenu.selectedCommaSeparatedValues();
}else{
let camNum=parseInt(elementNamed('cameraNum').value);
let deviceType=parseInt(elementNamed('deviceType').value);
if(_sg.camMenu.selectedValue()=='999')_sg.camMenu.setOption(_sg.camMenu.selectedIndex(),elementNamed('name').value,camNum);
if(deviceType!=kDeviceTypeNetwork){
document.getElementById('networkDeviceSettings').remove();
document.getElementById('advNetOptions').remove();
}
if(deviceType!=kDeviceTypeLocal && deviceType!=kDeviceTypeScreen && deviceType!=kDeviceTypeSimulated){
document.getElementById('localDeviceSettings').remove();
document.getElementById('advLocalOptions').remove();
}
if(deviceType!=kDeviceTypePush){
document.getElementById('pushDeviceSettings').remove();
document.getElementById('advPushOptions').remove();
}
if(!IsLocalhost()){
if(document.getElementById('configureHome'))document.getElementById('configureHome').remove();
if(document.getElementById('openInBrowser'))document.getElementById('openInBrowser').remove();
}
let camTab=allCookies.getItem('camTab');
document.getElementById('tab'+(camTab?camTab:'1')).checked=true;
document.getElementById('content'+(camTab?camTab:'1')).style.display='block';
document.getElementById('tab1').onchange=()=>{SgSelectCamTab(1)};
document.getElementById('tab2').onchange=()=>{SgSelectCamTab(2)};
document.getElementById('tab3').onchange=()=>{SgSelectCamTab(3)};
document.getElementById('tab4').onchange=()=>{SgSelectCamTab(4)};
document.getElementById('tab5').onchange=()=>{SgSelectCamTab(5)};
document.getElementById('tab6').onchange=()=>{SgSelectCamTab(6)};
_sg.maskPicker1=new MaskPicker(document.getElementById('previewImageDiv1'),camNum,document.getElementById('privacyMask').value,'rgba(0,0,0,1)',100);
_sg.maskPicker2=new MaskPicker(document.getElementById('previewImageDiv2'),camNum,document.getElementById('motionMask').value,'rgba(0,180,0,1)',70);
_sg.maskPicker3=new MaskPicker(document.getElementById('previewImageDiv3'),camNum,document.getElementById('presenceRect').value,'rgba(0,180,0,1)',60);
_sg.maskPicker2.cropSource=_sg.maskPicker1;
_sg.maskPicker3.cropSource=_sg.maskPicker1;
}
SgShowHideTriggerDivs();
SgShowHideShortcutDivs();
SgSliderSetup();
if(!isMulti){
SgSetUpAudioDeviceMenus();
SgProfileChanged();
}
}else{
document.getElementById('setForm').remove();
}
SgActionSoundChanged('Mac');
SgActionSoundChanged('Cam');
if(!_sg.camStatusTimer)_sg.camStatusTimer=setTimeout(SgGetCamStatus,0);
}
if(which=='email'){
if(elementNamed('sendingMethod').value==0)document.getElementById('smtpSettings').style.display='none';
}
if(which=='storage'){
SgRefreshDiskSpace('globalStorage');
SgRefreshDiskSpace('archiveStorage');
}
if(which=='web'){
AlignElementsLeft(elementNamed('portHttp'),elementNamed('portHttps'));
SgInitGeoblock();
}
if(which=='license'){
let textarea=document.getElementById('newFeatures');
if(textarea){
for(let fontSize=14;fontSize>10;fontSize--){
textarea.style.fontSize=fontSize+'px';
if(textarea.scrollWidth<=textarea.clientWidth)break;
}
textarea.style.height=textarea.scrollHeight+'px';
textarea.style.overflowX='hidden';
}
let updateRedDot=document.getElementById('updateRedDot');
let storeRedDot=document.getElementById('storeRedDot');
document.getElementById('licenseRedDot').style.display=((!updateRedDot || window.getComputedStyle(updateRedDot).display=='none')&&(!storeRedDot || window.getComputedStyle(storeRedDot).display=='none'))?'none':'block';
}
_sg.formData=SgCurrentFormData();
SgSetWarningIcons();
DisableTextInputHelpers();
}
function SgSelectCamTab(num){
for(let i=1;i<=6;i++)document.getElementById('content'+i).style.display=((i==num)?'block':'none');
allCookies.setItem('camTab',num,600);
}
function SgSelectSection(which){
if(_sg.which!=which){
SetRadioGroupValue('setTab',which);
SgFetchPage();
}
}
function SgSelectCam(camNum){
let current=_sg.camMenu.selectedValue();
current=(current==='')?-1:parseInt(current);
if(_sg.which=='cameras' && camNum==current)return;
if(camNum>-1)_sg.camMenu.selectValue(camNum);
SetRadioGroupValue('setTab','cameras');
SgFetchPage();
}
function SgEmailSendingMethodChanged(){
document.getElementById('smtpSettings').style.display=parseInt(elementNamed('sendingMethod').value)?'table-row-group':'none';
}
function SgProfileChanged(){
const profile=elementNamed('profile');
if(!profile)return;
const opt=profile.options[profile.selectedIndex];
const inputNum=elementNamed('inputNum');
const format=elementNamed('format');
const width=elementNamed('width');
const height=elementNamed('height');
const videoSizeButton=document.getElementById('videoSizeButton');
const fps=elementNamed('fps');
const quality=elementNamed('quality');
const request=elementNamed('request');
const setTime=document.getElementById('setTime');
const arr=opt.id.split(',');
const inputCount=parseInt(arr[0]);
const flags=parseInt(arr[1]);
const formatBits=parseInt(arr[2]);
if(inputNum){
inputNum.innerHTML="";
for(let i=0;i<inputCount;i++)inputNum.add(new Option((flags&kZeroBased)?i:i+1,i));
if(SelectValueIsValid(inputNum,document.getElementById('lastInputNum').value))inputNum.value=document.getElementById('lastInputNum').value;
else inputNum.selectedIndex=0;
}
if(format){
format.innerHTML="";
for(let i=0;i<kFormats.length;i++){
if(formatBits &(1<<i)){
let name=kFormats[i];
if(profile.value==kProfileSS)name=name.replaceAll('H.264','H.264 / H.265');
format.add(new Option(name,i));
}
}
if(document.getElementById('lastFormat')&& SelectValueIsValid(format,document.getElementById('lastFormat').value))format.value=document.getElementById('lastFormat').value;
else SgBestFormat(format);
}
if(width && height && fps && quality){
const capabilities=parseInt((kFormats[format.value].includes("RTSP"))?arr[4]:arr[3]);
if(capabilities&kSize){
width.disabled=false;
height.disabled=false;
videoSizeButton.disabled=false;
}else{
width.disabled=true;
height.disabled=true;
videoSizeButton.disabled=true;
width.value="";
height.value="";
}
if(capabilities&kRate){
fps.disabled=false;
}else{
fps.disabled=true;
fps.value="";
}
if(capabilities&kQuality){
quality.disabled=false;
}else{
quality.disabled=true;
quality.value=0;
}
}
if(profile.value==kProfileManual){
request.disabled=false;
}else{
request.disabled=true;
}
if(profile.value==kProfileOnvif){
setTime.disabled=false;
}else{
setTime.disabled=true;
setTime.checked=false;
}
}
function SgVideoSizeMenu(event){
let resolutions = [
{w: 7680,h: 4320,n: '8K / 33 MP'},
{w: 6016,h: 4016,n: '24 MP'},
{w: 5472,h: 3648,n: '20 MP'},
{w: 5120,h: 2880,n: '5K / 14 MP'},
{w: 4608,h: 3456,n: '16 MP'},
{w: 3840,h: 2160,n: '4K UHD / 8 MP'},
{w: 3072,h: 2048,n: '3K / 6 MP'},
{w: 2880,h: 1920},
{w: 2688,h: 1792},
{w: 2592,h: 1944,n: '5 MP'},
{w: 2560,h: 1440,n: '2.5K QHD / 4 MP'},
{w: 2448,h: 2048},
{w: 2304,h: 1728},
{w: 2048,h: 1536,n: 'QXGA'},
{w: 1920,h: 1080,n: 'HD / 2 MP'},
{w: 1600,h: 1200,n: 'UXGA'},
{w: 1440,h: 1080},
{w: 1280,h: 960},
{w: 1280,h: 720,n: 'HD / 1 MP'},
{w: 1024,h: 768,n: 'XGA'},
{w: 800,h: 600,n: 'SVGA'},
{w: 640,h: 480,n: 'VGA'},
{w: 352,h: 288,n: 'CIF'},
{w: 320,h: 240,n: 'QVGA'}];
let menu=new PopMenu(event);
menu.addSectionTitle(Loc('Common Video Sizes'));
resolutions.forEach(function(res){
menu.addItem(res.w+' x '+res.h+(res.n?' ('+res.n+')':''),false,function(){
elementNamed('width').value=res.w;
elementNamed('height').value=res.h;
});
});
}
function SgInputNumChanged(sel){
document.getElementById('lastInputNum').value=sel.value;
}
function SgFormatChanged(sel){
document.getElementById('lastFormat').value=sel.value;
}
function SgBestFormat(sel){
const order=[15,6,7,14,8,10];
for(let i=0;i<order.length;i++)if(SelectValueIsValid(sel,order[i])){sel.value=order[i];return;}
sel.selectedIndex=0;
}
function SgDiscoveredDevices(event,textBoxName){
try{
let menu=new PopMenu(event);
if(_devices.onvif && _devices.onvif.length)
{
menu.addSectionTitle(Loc('ONVIF Devices'));
_devices.onvif.forEach(function(d){
menu.addItem(d.name+' ('+d.ip+')',(d.used || elementNamed(textBoxName).value==d.id),function(){
elementNamed(textBoxName).value=d.id;
});
});
menu.addSeparator();
}
if(_devices.bonjour && _devices.bonjour.length)
{
menu.addSectionTitle(Loc('Bonjour Devices'));
_devices.bonjour.forEach(function(d){
menu.addItem(d.name+' ('+d.ip+')',(d.used || elementNamed(textBoxName).value==d.id),function(){
elementNamed(textBoxName).value=d.id;
});
});
}
if(!menu.length)menu.addItem(Loc('No devices found'),false,null);
}catch(error){}
}
function SgSssDiscoveredDevices(event){
try{
let menu=new PopMenu(event);
if(_devices.bonjour && _devices.bonjour.length)
{
_devices.bonjour.forEach(function(d){
if(d.profile==2)menu.addItem(d.name+' ('+d.ip+')',false,function(){
document.getElementById('sssAddress').value=d.id;
});
});
}
if(!menu.length)menu.addItem(Loc('No servers found'),false,null);
}catch(error){}
}
async function SgSave(){
let form=document.getElementById('setForm');
let postBody=GetFormKeyValueString(form);
if(_sg.which=='general'){
const p1=elementNamed('setPass');
const p2=elementNamed('fsPass');
const p3=elementNamed('quitPass');
const c1=(p1 && p1.value && p1.value!='****************' && !p1.dataset.confirmed);
const c2=(p2 && p2.value && p2.value!='****************' && !p2.dataset.confirmed);
const c3=(p3 && p3.value && p3.value!='****************' && !p3.dataset.confirmed);
if(c1||c2||c3){
SgConfirmPassBeforeSave(c1,c2,c3);
return;
}
document.getElementById('sysName').textContent=elementNamed('sysName').value;
}else if(_sg.which=='cameras'){
if(_sg.maskPicker1)postBody+='&privacyMask='+_sg.maskPicker1.maskStr();
if(_sg.maskPicker2)postBody+='&motionMask='+_sg.maskPicker2.maskStr();
if(_sg.maskPicker3)postBody+='&presenceRect='+_sg.maskPicker3.maskStr();
postBody+='&storage='+encodeURIComponent(document.getElementById('storage').textContent);
}else if(_sg.which=='display'){
const options=document.getElementById('groups').options;
for(let opt of options)postBody+='&group='+encodeURIComponent('{"name":'+JSON.stringify(opt.textContent)+',"id":'+opt.dataset.id+','+opt.value.slice(1));
}else if(_sg.which=='sched'){
let selS=document.getElementById('schedules');
let selP=document.getElementById('presets');
for(let opt of selS.options)postBody+='&sched='+encodeURIComponent('{"name":'+JSON.stringify(opt.textContent)+',"id":'+opt.dataset.id+',"objects":'+opt.value+'}');
for(let opt of selP.options)postBody+='&preset='+encodeURIComponent('{"name":'+JSON.stringify(opt.textContent)+',"id":'+opt.dataset.id+','+opt.value.slice(1));
}else if(_sg.which=="storage"){
postBody+='&globalStorage='+encodeURIComponent(document.getElementById('globalStorage').textContent);
postBody+='&archiveStorage='+encodeURIComponent(document.getElementById('archiveStorage').textContent);
}else if(_sg.which=='uploads'){
let sel=document.getElementById('uploads');
for(let opt of sel.options)
postBody+='&upload='+encodeURIComponent('{"name":'+JSON.stringify(opt.textContent)+',"id":'+opt.dataset.id+','+opt.value.slice(1));
}else if(_sg.which=='web'){
let sel=document.getElementById('accounts');
for(let opt of sel.options)postBody+='&account='+encodeURIComponent('{"id":'+opt.dataset.id+','+opt.value.slice(1));
}
try{
const result=await fetch(document.getElementById('setForm').action,{
credentials:'same-origin',
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:postBody
});
if(result.status==200){
document.getElementById('saveButton').innerHTML=Loc('Save')+' &#10004;';
document.getElementById('setErr').innerHTML='';
if(_sg.tickTimer)clearTimeout(_sg.tickTimer);
_sg.tickTimer=setTimeout(SgHideTick,4000);
const data=await result.json();
if(data.reload)window.location='/';
else if(data.camUpdate)SgProcessCamUpdate(data.camUpdate);
}else{
throw new Error('Error: '+result.status);
}
}catch(error){
document.getElementById('setErr').innerHTML=error;
}
_sg.formData=SgCurrentFormData();
}
function SgHideTick(){
document.getElementById('saveButton').textContent=Loc('Save');
_sg.tickTimer=null;
}
function SgCamSelectionChanged(){
let selectedCount=_sg.camMenu.selectedCount();
document.getElementById('camDeleteButton').disabled=selectedCount?false:true;
document.getElementById('setTabCameras').checked=true;
if(selectedCount>1 && document.getElementById('setForm')&& document.getElementById('setForm').action.endsWith('-multi')){
elementNamed('cameras').value=_sg.camMenu.selectedCommaSeparatedValues();
return;
}
SgFetchPage();
}
function SgCamRename(newName,camNum){
elementNamed('name').value=newName;
}
function SgCamAdd(event){
try{
let menu=new PopMenu(event);
menu.addItem(Loc('Add Network Device'),false,function(){
SgCamDoAdd(kDeviceTypeNetwork,{name:Loc('Untitled Camera'),id:''});
});
if(!_devices.onvif)return;
menu.addSeparator();
if(_devices.onvif.length){
_devices.onvif.forEach(function(d){
menu.addItem(Loc('Add ONVIF Device {0}',d.name),d.used,function(){
SgCamDoAdd(kDeviceTypeNetwork,d);
});
});
menu.addSeparator();
}
if(_devices.bonjour.length){
_devices.bonjour.forEach(function(d){
menu.addItem(Loc('Add Bonjour Device {0}',d.name),d.used,function(){
SgCamDoAdd(kDeviceTypeNetwork,d);
});
});
menu.addSeparator();
}
if(_devices.local.length){
_devices.local.forEach(function(d){
menu.addItem(Loc('Add Local Device {0}',d.name),d.used,function(){
SgCamDoAdd(kDeviceTypeLocal,d);
});
});
menu.addSeparator();
}
if(_devices.simulated.length){
_devices.simulated.forEach(function(d){
menu.addItem(Loc('Add Simulated Device {0}',d.name),d.used,function(){
SgCamDoAdd(kDeviceTypeSimulated,d);
});
});
menu.addSeparator();
}
if(_devices.screen.length){
_devices.screen.forEach(function(d){
menu.addItem(Loc('Add Screen Device {0}',d.name),d.used,function(){
SgCamDoAdd(kDeviceTypeScreen,d);
});
});
menu.addSeparator();
}
if(_oemId==3){
menu.addItem(Loc('Add Push Device'),false,function(){
SgCamDoAdd(kDeviceTypePush,{name:Loc('Untitled Camera'),id:''});
});
menu.addSeparator();
}
menu.addItem(Loc('Add All Cameras From SecuritySpy Server…'),false,function(){
document.getElementById('sssPanel').style.display='flex';
});
menu.addItem(Loc('Add Multiple Cameras From NVR…'),false,function(){
let countMenu=document.getElementById('nvrCount');
if(!countMenu.options.length)for(let i=1;i<=32;i++)countMenu.add(new Option(i,i));
document.getElementById('nvrPanel').style.display='flex';
});
}catch(error){}
}
function SgCamDoAdd(deviceType,d){
_sg.camMenu.selectIndex(_sg.camMenu.addOption(d.name,999));
document.getElementById('camDeleteButton').disabled=false;
document.getElementById('camGearButton').disabled=false;
document.getElementById('setTabCameras').checked=true;
SgFetchPage(null,'deviceType='+deviceType+'&name='+encodeURIComponent(d.name)+'&id='+d.id+'&profile='+(d.profile?d.profile:''));
if(d)d.used=true;
}
function SgCamDelete(){
let selectedOptions=_sg.camMenu.selectedOptions();
if(!selectedOptions.length)return;
let alert=new Alert((selectedOptions.length>1)?Loc('delete_selected'):Loc('delete_cam',selectedOptions[0].name),Loc('This operation cannot be undone'));
alert.addButton(Loc('Delete'),function(){
let list=_sg.camMenu.selectedCommaSeparatedValues();
_sg.camMenu.removeSelectedOptions();
SgFetchPage(null,'deleteCams='+list,true);
});
alert.addButton(Loc('Cancel'),null);
}
function SgCamGearMenu(event){
try{
let menu=new PopMenu(event);
menu.addItem(Loc('Reorder Cameras'),false,function(){
new CamSorter(_sg.camMenu.options(),function(arr){
SgSetCamOrder(arr);
});
});
for(let opt of _sg.camMenu.selectedOptions()){
menu.addItem(Loc('Duplicate {0}',opt.name),false,function(){
SgDuplicateCam(opt.value);
});
}
if(_oemId==3){
for(let opt of _sg.camMenu.selectedOptions()){
let cam=CamFromNum(opt.value);
if(cam.type==kDeviceTypeNetwork){
menu.addItem(Loc('Change {0} to Push',opt.name),false,function(){
SgChangeDeviceType(opt.value,kDeviceTypePush);
});
}else if(cam.type==kDeviceTypePush){
menu.addItem(Loc('Change {0} to Network',opt.name),false,function(){
SgChangeDeviceType(opt.value,kDeviceTypeNetwork);
});
}
}
}
for(let i=1;i<_groups.length;i++){
menu.addItem(Loc('Select All Cameras In Group {0}',_groups[i].name),false,function(){
_sg.camMenu.selectValues(_groups[i].members);
SgFetchPage();
});
}
}catch(error){}
}
function SgDuplicateCam(camNum){
let newIndex=_sg.camMenu.addOption(Loc('New Camera'),999);
_sg.camMenu.selectIndex(newIndex);
SgFetchPage(null,'dupCam='+camNum);
}
function SgChangeDeviceType(camNum,newType){
_sg.camMenu.selectValue(camNum);
for(let c of _cams)if(c.num == camNum){c.type = newType;break;}
SgFetchPage(null,'newDeviceType='+newType);
}
function SgSetCamOrder(arr){
_sg.camMenu.setOrder(arr);
const cams=[];
for(let i of arr){
for(let c of _cams)if(c.num==i){cams.push(c);break;}
}
_cams=cams;
fetch('settings-order',{
credentials:'same-origin',
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:'order='+arr.join()
});
}
function SgProcessCamUpdate(info){
let index=_sg.camMenu.indexFromValue(info.num);
if(index<0)return;
_sg.camMenu.setOption(index,info.name,info.num);
if(_sg.which=='cameras' && elementNamed('cameraNum')&& elementNamed('cameraNum').value==info.num){
elementNamed('name').value=info.name;
}
}
function SgGroupAdd(){
if(document.getElementById('groups').options.length>31){
let alert=new Alert(Loc('The maximum number of groups has been reached'));
alert.addButton('OK',null);
}else{
SgShowGroupEditPanel(null);
}
}
function SgGroupDelete(){
const sel=document.getElementById('groups');
if(sel.selectedIndex>-1){
sel.remove(sel.selectedIndex);
SgGroupSelectionChange();
}
}
function SgGroupEdit(){
const sel=document.getElementById('groups');
if(sel.selectedIndex>-1)SgShowGroupEditPanel(sel.selectedIndex);
}
function SgGroupSelectionChange(){
if(document.getElementById('groups').selectedIndex<0){
document.getElementById('groupDeleteButton').disabled=true;
document.getElementById('groupEditButton').disabled=true;
}else{
document.getElementById('groupDeleteButton').disabled=false;
document.getElementById('groupEditButton').disabled=false;
}
}
function SgShowGroupEditPanel(index){
const panel=document.getElementById('groupPanel');
const boxes=panel.querySelectorAll('input[type="checkbox"]');
const sel=document.getElementById('groups');
const groupName=document.getElementById('groupName');
panel.dataset.isNew=(index==null)?"1":"0";
for(let box of boxes)box.checked=false;
let d={};
if(index==null){
groupName.value=Loc('Untitled Group');
}else{
groupName.value=sel.options[index].textContent;
d=JSON.parse(sel.options[index].value);
if(d.cameras!=null){
for(cam of d.cameras){
const checkbox=document.getElementById('check'+cam);
if(checkbox)checkbox.checked=true;
}
}
}
if(d.displayType==null)d.displayType=0;
if(d.cycleSeconds==null || d.cycleSeconds<1)d.cycleSeconds=10;
document.getElementById('displayType').value=d.displayType;
document.getElementById('cycleSeconds').value=d.cycleSeconds;
panel.style.display='flex';
}
function SgGroupSave(){
const panel=document.getElementById('groupPanel');
const boxes=panel.querySelectorAll('input[type="checkbox"]:checked');
const sel=document.getElementById('groups');
const groupName=document.getElementById('groupName');
const d={displayType:0,cycleSeconds:10,cameras:[]};
d.displayType=parseInt(document.getElementById('displayType').value);
d.cycleSeconds=parseInt(document.getElementById('cycleSeconds').value);
for(let box of boxes)d.cameras.push(parseInt(box.id.slice(5)));
if(panel.dataset.isNew=="1"){
sel.add(new Option());
sel.selectedIndex=sel.length-1;
sel.options[sel.selectedIndex].dataset.id=SgUniqueGroupID();
}
sel.options[sel.selectedIndex].textContent=groupName.value?groupName.value:Loc('Untitled Group');
sel.options[sel.selectedIndex].value=JSON.stringify(d);
panel.style.display='none';
SgGroupSelectionChange();
}
function SgGroupCancel(){
const panel=document.getElementById('groupPanel');
panel.style.display='none';
SgGroupSelectionChange();
}
function SgGroupCamChanged(event){
if(event && event.altKey){
let container=document.getElementById('groupCams');
let boxes=container.querySelectorAll('input[type="checkbox"]');
for(let box of boxes)box.checked=event.target.checked;
}
}
function SgUniqueGroupID(){
const sel=document.getElementById('groups');
const res=elementNamed('reservedGroupIds').value?elementNamed('reservedGroupIds').value.split(",").map(Number):[];
for(i=0;i<sel.options.length;i++)res.push(parseInt(sel.options[i].dataset.id));
for(let i=0;;){
let id=Math.floor(Math.random()*255)+1;
if(!res.includes(id))return id;
}
}
function SgScheduleSelectionChange(){
if(document.getElementById('schedules').selectedIndex<0){
document.getElementById('sDeleteButton').disabled=true;
document.getElementById('sEditButton').disabled=true;
}else{
document.getElementById('sDeleteButton').disabled=false;
document.getElementById('sEditButton').disabled=false;
}
}
function SgScheduleAdd(){
let sel=document.getElementById('schedules');
new SchedulePicker(null,'[]',function(name,json){
let opt=AddElement(sel,'option');
opt.textContent=name;
opt.value=json;
opt.dataset.id=SgUniqueScheduleID();
sel.selectedIndex=sel.length-1;
SgScheduleSelectionChange();
});
}
function SgScheduleEdit(){
let sel=document.getElementById('schedules');
if(sel.selectedIndex<0)return;
let opt=sel.options[sel.selectedIndex];
new SchedulePicker(opt.textContent,opt.value,function(name,json){
opt.textContent=name;
opt.value=json;
});
}
function SgScheduleDelete(){
const sel=document.getElementById('schedules');
if(sel.selectedIndex>-1){
sel.remove(sel.selectedIndex);
SgScheduleSelectionChange();
}
}
function SgUniqueScheduleID(){
const sel=document.getElementById('schedules');
for(let i=0;;){
let id=Math.floor(Math.random()*65530)+5;
for(i=0;i<sel.options.length;i++)if(parseInt(sel.options[i].dataset.id)==id)break;
if(i==sel.options.length)return id;
}
}
function SgPresetSelectionChange(){
if(document.getElementById('presets').selectedIndex<0){
document.getElementById('pDeleteButton').disabled=true;
document.getElementById('pEditButton').disabled=true;
}else{
document.getElementById('pDeleteButton').disabled=false;
document.getElementById('pEditButton').disabled=false;
}
}
function SgPresetAdd(){
let sel=document.getElementById('presets');
new SchedulePresetPicker(null,'{}',function(name,json){
let opt=AddElement(sel,'option');
opt.textContent=name;
opt.value=json;
opt.dataset.id=SgUniquePresetID();
sel.selectedIndex=sel.length-1;
SgPresetSelectionChange();
});
}
function SgPresetEdit(){
let sel=document.getElementById('presets');
if(sel.selectedIndex<0)return;
let opt=sel.options[sel.selectedIndex];
new SchedulePresetPicker(opt.textContent,opt.value,function(name,json){
opt.textContent=name;
opt.value=json;
});
}
function SgPresetDelete(){
const sel=document.getElementById('presets');
if(sel.selectedIndex>-1){
sel.remove(sel.selectedIndex);
SgPresetSelectionChange();
}
}
function SgUniquePresetID(){
const sel=document.getElementById('presets');
for(let i=0;;){
let id=Math.floor(Math.random()*4294967295)+1;
for(i=0;i<sel.options.length;i++)if(parseInt(sel.options[i].dataset.id)==id)break;
if(i==sel.options.length)return id;
}
}
function SgEditSelectOption(sel){
if(sel.selectedIndex<0)return;
let opt=sel.options[sel.selectedIndex];
let r=opt.getBoundingClientRect();
let txt=AddElement(document.body,'input','z-index:1;box-sizing:border-box;position:absolute;left:'+r.left+'px;top:'+r.top+'px;width:'+(r.right-r.left)+'px;height:'+(r.bottom-r.top)+';');
txt.type='text';
txt.value=opt.innerText;
txt.select();
txt.focus();
txt.onblur=()=>{
txt.remove();
};
txt.onkeydown=(e)=>{
if(e.key=='Enter' || e.keyCode==13){
if(txt.value.length>0)opt.innerText=txt.value;
txt.blur();
}else if(e.key=='Escape' || e.keyCode==27){
txt.blur();
}
};
}
function SgAutoThresholdCheckboxClick(check,textBoxName){
let txtBox=elementNamed(textBoxName);
if(check.checked){
txtBox.value='';
txtBox.disabled=true;
}else{
txtBox.value='50';
txtBox.disabled=false;
}
}
function SgStorageNewPath(newPath,pathElementId){
if(!pathElementId && document.getElementById('tempFileElement'))pathElementId=document.getElementById('tempFileElement').dataset.pathElementId;
if(!pathElementId)return;
let prefix='/Volumes/'+document.getElementById('userVolName').value;
if(newPath.startsWith(prefix+'/Users/'))newPath=newPath.slice(prefix.length);
if(document.getElementById(pathElementId).textContent!=newPath){
document.getElementById(pathElementId).textContent=newPath;
if(document.getElementById(pathElementId+'Warning'))document.getElementById(pathElementId+'Warning').style.display='none';
SgRefreshDiskSpace(pathElementId);
}
if(document.getElementById('tempFileElement'))document.getElementById('tempFileElement').remove();
}
function SgStorageSet(pathElementId){
let path=document.getElementById(pathElementId).textContent;
if(path.startsWith('Unset'))path='';
if(_isSettingsWindow){
if(document.getElementById('tempFileElement'))document.getElementById('tempFileElement').remove();
window.webkit.messageHandlers.path.postMessage(path);
let input=AddElement(document.body,'input');
input.id='tempFileElement';
input.type='file';
input.multiple=false;
input.webkitdirectory=true;
input.dataset.pathElementId=pathElementId;
input.click();
}else{
new FolderPicker(path,function(newPath){
if(newPath)SgStorageNewPath(newPath,pathElementId);
});
}
}
function SgStorageClear(pathElementId){
if(document.getElementById(pathElementId).textContent!=document.getElementById(pathElementId+'Default').value){
document.getElementById(pathElementId).textContent=document.getElementById(pathElementId+'Default').value;
if(document.getElementById(pathElementId+'Warning'))document.getElementById(pathElementId+'Warning').style.display='none';
SgRefreshDiskSpace(pathElementId);
}
}
async function SgRefreshDiskSpace(pathElementId){
let td=document.getElementById(pathElementId+'Usage');
if(document.getElementById(pathElementId)&& td){
let path=document.getElementById(pathElementId).textContent;
if(!path || path.startsWith('Unset')){td.innerHTML='';return;}
let result=await fetch('diskInfo?path='+encodeURIComponent(path),{credentials:'same-origin'});
let info=await result.json();
td=document.getElementById(pathElementId+'Usage');
if(td){
if(info.err)td.innerHTML=Loc("Couldn't get disk info ({0} {1})",info.err,info.errDesc);
else td.innerHTML='<progress id="diskProgress" max="100" value="'+info.percent+'"></progress>'+Loc('{0}% full ({1} used of {2})',info.percent,info.used,info.total);
}
}
}
function SgUploadSelectionChange(){
if(document.getElementById('uploads').selectedIndex<0){
document.getElementById('deleteButton').disabled=true;
document.getElementById('editButton').disabled=true;
}else{
document.getElementById('deleteButton').disabled=false;
document.getElementById('editButton').disabled=false;
}
}
function SgUploadAdd(){
SgSetupUploadControls(null);
document.getElementById('uploadPanel').style.display='flex';
}
function SgUploadEdit(){
const sel=document.getElementById('uploads');
SgSetupUploadControls(sel.options[sel.selectedIndex]);
document.getElementById('uploadPanel').style.display='flex';
}
function SgUploadDelete(){
const sel=document.getElementById('uploads');
if(sel.selectedIndex>-1){
sel.remove(sel.selectedIndex);
SgUploadSelectionChange();
}
}
function SgUploadCancel(){
document.getElementById('uploadPanel').style.display='none';
}
function SgUploadSave(){
let sel=document.getElementById('uploads');
let opt=sel.options[sel.selectedIndex];
if(!document.getElementById('uploadId').value){
opt=AddElement(sel,'option');
opt.dataset.id=SgUniqueUploadID();
sel.selectedIndex=sel.length-1;
}
opt.textContent=document.getElementById('name').value?document.getElementById('name').value:Loc('Untitled Destination');
opt.value=SgUploadControlsToJson();
document.getElementById('uploadPanel').style.display='none';
SgUploadSelectionChange();
}
function SgSetupUploadControls(option){
document.getElementById('protocol').value=0;
document.getElementById('name').value=Loc('Untitled Destination');
document.getElementById('uploadId').value='';
document.getElementById('address').value='';
document.getElementById('username').value='';
document.getElementById('password').value='';
document.getElementById('bucket').value='';
document.getElementById('path').value='';
document.getElementById('testResult').innerHTML='';
document.getElementById('appendCamName').checked=false;
document.getElementById('appendDirName').checked=false;
if(option){
const d=JSON.parse(option.value);
if(option.innerText)document.getElementById('name').value=option.innerText;
if(option.dataset.id)document.getElementById('uploadId').value=option.dataset.id;
if(d.protocol!=null)document.getElementById('protocol').value=d.protocol;
if(d.address!=null)document.getElementById('address').value=d.address;
if(d.username!=null)document.getElementById('username').value=d.username;
if(d.password!=null)document.getElementById('password').value=d.password;
if(d.bucket!=null)document.getElementById('bucket').value=d.bucket;
if(d.path!=null)document.getElementById('path').value=d.path;
if(d.appendCamName!=null)document.getElementById('appendCamName').checked=d.appendCamName?true:false;
if(d.appendDirName!=null)document.getElementById('appendDirName').checked=d.appendDirName?true:false;
}
SgUploadProtocolChanged();
}
function SgUploadControlsToJson(){
const d={protocol:parseInt(document.getElementById('protocol').value),
address:document.getElementById('address').value,
username:document.getElementById('username').value,
password:document.getElementById('password').value,
bucket:document.getElementById('bucket').value,
path:document.getElementById('path').value,
appendCamName:document.getElementById('appendCamName').checked,
appendDirName:document.getElementById('appendDirName').checked};
return JSON.stringify(d);
}
function SgUniqueUploadID(){
const sel=document.getElementById('uploads');
for(let i=0;;){
let id=Math.floor(Math.random()*4294967295)+1;
for(i=0;i<sel.options.length;i++)if(parseInt(sel.options[i].dataset.id)==id)break;
if(i==sel.options.length)return id;
}
}
function SgUploadProtocolChanged(){
let protocol=parseInt(document.getElementById('protocol').value);
document.getElementById('addressLabel').textContent=(protocol==kUploadTypeS3)?Loc('Endpoint (optional):'):Loc('Server address:');
document.getElementById('usernameLabel').textContent=(protocol==kUploadTypeS3)?Loc('Access key ID:'):Loc('Username:');
document.getElementById('passwordLabel').textContent=(protocol==kUploadTypeS3)?Loc('Secret access key:'):Loc('Password:');
document.getElementById('bucket').disabled=(protocol==kUploadTypeS3)?false:true;
if(protocol!=kUploadTypeS3)document.getElementById('bucket').value='';
document.getElementById('address').disabled=(protocol==kUploadTypeLocal)?true:false;
document.getElementById('username').disabled=(protocol==kUploadTypeLocal)?true:false;
document.getElementById('password').disabled=(protocol==kUploadTypeLocal)?true:false;
document.getElementById('set').style.display=(protocol==kUploadTypeLocal)?'inline':'none';
if(protocol==kUploadTypeLocal){
document.getElementById('address').value='';
document.getElementById('username').value='';
document.getElementById('password').value='';
document.getElementById('bucket').value='';
}
}
function SgUploadChoosePath(){
new FolderPicker(null,function(newPath){
if(newPath)document.getElementById('path').value=newPath;
});
}
async function SgUploadTest(){
const testResult=document.getElementById('testResult');
const testButton=document.getElementById('testButton');
testResult.textContent=Loc('Testing connection…');
testButton.disabled=true;
try{
let result=await fetch('testUpload'+
'?id='+document.getElementById('uploadId').value+
'&protocol='+document.getElementById('protocol').value+
'&address='+encodeURIComponent(document.getElementById('address').value)+
'&username='+encodeURIComponent(document.getElementById('username').value)+
'&password='+encodeURIComponent(document.getElementById('password').value)+
'&bucket='+encodeURIComponent(document.getElementById('bucket').value)+
'&path='+encodeURIComponent(document.getElementById('path').value),
{credentials:'same-origin'});
let txt=await result.text();
if(result.ok)testResult.textContent=Loc('The file was transferred successfully');
else testResult.textContent=Loc('Error {0} {1}',result.status,txt);
}catch(error){
testResult.textContent=error;
}
testButton.disabled=false;
}
async function SgEmailTest(){
const testResult=document.getElementById('testResult');
const testButton=document.getElementById('testButton');
const testDst=document.getElementById('testDst').value;
if(!IsValidEmail(testDst)){testResult.textContent=Loc('Please enter a valid destination email address');return;}
testResult.textContent=Loc('Sending test email…');
testButton.disabled=true;
try{
let result=await fetch('testEmail'+
'?sendingMethod='+elementNamed('sendingMethod').value+
'&address='+encodeURIComponent(elementNamed('address').value)+
'&fromEmail='+encodeURIComponent(elementNamed('fromEmail').value)+
'&fromName='+encodeURIComponent(elementNamed('fromName').value)+
'&username='+encodeURIComponent(elementNamed('username').value)+
'&password='+encodeURIComponent(elementNamed('password').value)+
'&encryption='+elementNamed('encryption').value+
'&testDst='+encodeURIComponent(testDst),
{credentials:'same-origin'});
let txt=await result.text();
if(result.ok)testResult.textContent=Loc('The email was sent successfully');
else testResult.textContent='Error '+result.status+': '+txt;
}catch(error){
testResult.textContent=error;
}
testButton.disabled=false;
}
function SgAccountSelectionChange(){
const sel=document.getElementById('accounts');
if(sel.selectedIndex>-1){
document.getElementById('accDeleteButton').disabled=false;
document.getElementById('accEditButton').disabled=false;
}else{
document.getElementById('accDeleteButton').disabled=true;
document.getElementById('accEditButton').disabled=true;
}
}
function SgAccountEdit(){
const sel=document.getElementById('accounts');
if(sel.selectedIndex<0)return;
new AccountPicker(sel.value,function(name,content){
if(name)sel.options[sel.selectedIndex].textContent=name;
if(content)sel.options[sel.selectedIndex].value=content;
});
}
function SgAccountAdd(){
new AccountPicker('{}',function(displayName,content){
if(content){
let opt=new Option(displayName,content);
opt.dataset.id=SgUniqueAccountID();
document.getElementById('accounts').add(opt);
}
});
}
function SgAccountDelete(){
const sel=document.getElementById('accounts');
if(sel.selectedIndex>-1){
sel.remove(sel.selectedIndex);
_sg.accountSelected=-1;
SgAccountSelectionChange();
}
}
function SgUniqueAccountID(){
const sel=document.getElementById('accounts');
for(let i=0;;){
let id=Math.floor(Math.random()*2147483647)+1;
for(i=0;i<sel.options.length;i++)if(parseInt(sel.options[i].dataset.id)==id)break;
if(i==sel.options.length)return id;
}
}
async function SgDdnsTest(){
const name=elementNamed('ddnsName');
const status=document.getElementById('ddnsStatus');
const test=document.getElementById('ddnsTest');
const feedback=document.getElementById('ddnsFeedback');
if(name.value.length<3){
feedback.textContent=Loc('DDNS name too short');
status.src='../img/status-red.png';
return;
}
status.src='../img/spinner.png';
status.style.animation='spin 1s linear infinite';
test.disabled=true;
try{
let result=await fetch('testDdns?sub='+elementNamed('ddnsName').value,{credentials:'same-origin'});
let txt=await result.text();
if(result.ok)feedback.textContent='';
else feedback.textContent=txt;
}catch(error){
feedback.textContent=error;
}
if(feedback.textContent.length)status.src='../img/status-red.png';
else status.src='../img/status-green.png';
status.style.animation='';
test.disabled=false;
}
async function SgGetCamStatus(){
let delay=3000;
try{
let result=await fetch('camStatus',{credentials:'same-origin'});
if(!result.ok)throw new Error('HTTP status '+result.status);
let array=await result.json();
for(let cam of array){
let tooltip='';
if(cam.online)tooltip=Loc('Online');
else if(!cam.enabled)tooltip=Loc('Disabled');
else if(cam.open)tooltip=Loc('Connecting');
else if(cam.err)tooltip=Loc('Error {0} {1}',cam.err,cam.errDesc);
_sg.camMenu.setStatusForValue(cam.num,cam.enabled?(cam.online?'&#9679;':(cam.open?'&ctdot;':'!')):'&#9675;',tooltip);
}
}catch(error){
delay*=5;
_sg.camMenu.removeAllStatus();
}
if(_sg.which=='cameras')_sg.camStatusTimer=setTimeout(SgGetCamStatus,delay);
else _sg.camStatusTimer=null;
}
async function SgGetDeviceList(){
try{
let result=await fetch('deviceList',{credentials:'same-origin'});
if(!result.ok)throw new Error('HTTP status '+result.status);
_devices=await result.json();
}catch(error){
}
}
function SgCurrentFormData(){
let form=document.getElementById('setForm');
if(!form)return '';
let str='';
for(let e of form.querySelectorAll('input')){
if(e.name!='tabs' && e.id!='testDst'){
if(e.type=='checkbox' || e.type=='radio')str+=e.checked?'1':'0';
else str+=e.value;
}
}
for(let e of form.querySelectorAll('select')){
if(e.id=='accounts' || e.id=='uploads' || e.id=='groups' || e.id=='schedules' || e.id=='presets'){
for(let o of e.options)str+=o.value+o.textContent;
}else{
str+=e.value;
}
}
if(_sg.maskPicker1)str+=_sg.maskPicker1.maskStr();
if(_sg.maskPicker2)str+=_sg.maskPicker2.maskStr();
if(_sg.maskPicker3)str+=_sg.maskPicker3.maskStr();
if(document.getElementById('storage'))str+=document.getElementById('storage').textContent;
if(document.getElementById('globalStorage'))str+=document.getElementById('globalStorage').textContent;
if(document.getElementById('archiveStorage'))str+=document.getElementById('archiveStorage').textContent;
return str+'set';
}
function ShowPopMessage(event,msg){
if(event.target.style.visibility=='hidden')return;
let div=AddElement(document.body,'div');
div.className='popBox';
div.innerHTML=msg;
let divLeft=window.pageXOffset+event.clientX-6;
let divTop=window.pageYOffset+event.clientY-6;
div.style.left=divLeft+'px';
div.style.top=divTop+'px';
let divRect=div.getBoundingClientRect();
if(divRect.right>window.pageXOffset+window.innerWidth)div.style.left=(divLeft-divRect.right+window.pageXOffset+window.innerWidth)+'px';
if(divRect.bottom>window.pageYOffset+window.innerHeight)div.style.top=(divTop-divRect.bottom+window.pageYOffset+window.innerHeight)+'px';
div.onmouseout=function(){
div.remove();
};
}
function SgOpenInBrowser(){
let addr=elementNamed('address').value;
let ssl=document.getElementById('sslHttp').checked;
let port=elementNamed(ssl?'portHttps':'portHttp').value;
let ndt=elementNamed('profile').value;
if(addr.startsWith("uuid:")){
if(_devices.onvif){
for(dev of _devices.onvif){
if(dev.id==addr){addr=dev.ip;break;}
}
}
if(addr.startsWith("uuid:")){
SimpleAlert(Loc('The address of the ONVIF device could not be determined.'),Loc('The device may no longer exist on your network.'));
return;
}
}
if(!port){
if(ndt==2)port=ssl?8001:8000;
else if(ndt==207)port=8065;
}
let url=(ssl?'https':'http')+'://'+addr+(port?':'+port:'');
fetch('openUrl?url='+encodeURIComponent(url),{credentials:'same-origin'});
}
function SgSetWarningIcons(){
if(_sg.which=='web'){
let e1=elementNamed('portHttp');
let e2=elementNamed('portHttps');
if(document.getElementById('portHttpWarning'))document.getElementById('portHttpWarning').style.display=(!e1.value || parseInt(e1.value)<1024)?'inline':'none';
if(document.getElementById('portHttpsWarning'))document.getElementById('portHttpsWarning').style.display=(!e2.value || parseInt(e2.value)<1024)?'inline':'none';
if(document.getElementById('samePortWarning'))document.getElementById('samePortWarning').style.display=(e1.value && e1.value==e2.value)?'inline':'none';
if(document.getElementById('warningSpan'))document.getElementById('warningSpan').style.display=((document.getElementById('http').checked || document.getElementById('https').checked)&& document.getElementById('accounts').options.length<1)?'block':'none';
if(document.getElementById('doubleNatWarning'))document.getElementById('doubleNatWarning').style.display=(elementNamed('doubleNat').value &&(document.getElementById('autoNatHttp').checked || document.getElementById('autoNatHttps').checked))?'inline':'none';
if(document.getElementById('cgNatWarning'))document.getElementById('cgNatWarning').style.display=(elementNamed('cgNat').value &&(document.getElementById('autoNatHttp').checked || document.getElementById('autoNatHttps').checked))?'inline':'none';
if(document.getElementById('insecureWanWarning'))document.getElementById('insecureWanWarning').style.display=document.getElementById('autoNatHttp').checked?'inline':'none';
}
if(_sg.which=='storage'){
if(document.getElementById('archiveWarning')&& elementNamed('archiveMode'))document.getElementById('archiveWarning').style.display=(parseInt(elementNamed('archiveMode').value)==0 && document.getElementById('archiveStorage').textContent && !document.getElementById('archiveStorage').textContent.startsWith('Unset')&& !document.getElementById('removeBySpace').checked)?'':'none';
}
if(_sg.which=='comp'){
if(document.getElementById('proResWarning'))document.getElementById('proResWarning').style.display=SelectedName(elementNamed('videoCodec')).startsWith('ProRes')?'':'none';
if(document.getElementById('h265Warning'))document.getElementById('h265Warning').style.display=(!_isAppleSilicon && SelectedName(elementNamed('videoCodec')).startsWith('H.265'))?'':'none';
if(document.getElementById('videoQualityWarning'))document.getElementById('videoQualityWarning').style.visibility=(parseInt(elementNamed('videoQuality').value)>75)?'':'hidden';
if(document.getElementById('audioQualityWarning'))document.getElementById('audioQualityWarning').style.visibility=(parseInt(elementNamed('audioQuality').value)>75)?'':'hidden';
if(document.getElementById('jpegQualityWarning'))document.getElementById('jpegQualityWarning').style.visibility=(parseInt(elementNamed('jpegQuality').value)>75)?'':'hidden';
}
if(_sg.which=='cameras' && elementNamed('deviceType')){
if(elementNamed('deviceType').value==kDeviceTypeNetwork){
let recompressChecked=document.getElementById('recompressVideo').checked;
if(document.getElementById('recompressWarning'))document.getElementById('recompressWarning').style.visibility=recompressChecked?'':'hidden';
if(document.getElementById('transWarning'))document.getElementById('transWarning').style.visibility=(elementNamed('transformation').selectedIndex && !recompressChecked)?'':'hidden';
if(document.getElementById('brightnessWarning'))document.getElementById('brightnessWarning').style.visibility=(parseInt(elementNamed('brightness').value)&& !recompressChecked)?'':'hidden';
if(document.getElementById('contrastWarning'))document.getElementById('contrastWarning').style.visibility=(parseInt(elementNamed('contrast').value)&& !recompressChecked)?'':'hidden';
if(document.getElementById('fisheyeWarning'))document.getElementById('fisheyeWarning').style.visibility=(elementNamed('fisheyeType').selectedIndex && !recompressChecked)?'':'hidden';
if(document.getElementById('overlayWarning'))document.getElementById('overlayWarning').style.visibility=elementNamed('overlayText').value.length?'':'hidden';
if(document.getElementById('ccFpsWarning'))document.getElementById('ccFpsWarning').style.visibility=(parseInt(elementNamed('ccMovieFps').value)&& !recompressChecked)?'':'hidden';
if(document.getElementById('mcFpsWarning'))document.getElementById('mcFpsWarning').style.visibility=(parseInt(elementNamed('mcMovieFps').value)&& !recompressChecked)?'':'hidden';
if(document.getElementById('maskWarning'))document.getElementById('maskWarning').style.visibility=(_sg.maskPicker1.isMask()&& !recompressChecked)?'':'hidden';
}else{
if(document.getElementById('transWarning'))document.getElementById('transWarning').style.display='none';
if(document.getElementById('brightnessWarning'))document.getElementById('brightnessWarning').style.display='none';
if(document.getElementById('contrastWarning'))document.getElementById('contrastWarning').style.display='none';
if(document.getElementById('overlayWarning'))document.getElementById('overlayWarning').style.display='none';
if(document.getElementById('fisheyeWarning'))document.getElementById('fisheyeWarning').style.display='none';
if(document.getElementById('ccFpsWarning'))document.getElementById('ccFpsWarning').style.display='none';
if(document.getElementById('mcFpsWarning'))document.getElementById('mcFpsWarning').style.display='none';
if(document.getElementById('maskWarning'))document.getElementById('maskWarning').style.display='none';
}
if(document.getElementById('mcMoviePostWarning'))document.getElementById('mcMoviePostWarning').style.visibility=(parseInt(elementNamed('mcMoviePost').value)<10)?'':'hidden';
if(document.getElementById('timelapseWarning'))document.getElementById('timelapseWarning').style.visibility=parseInt(elementNamed('ccMoviePlaybackFps').value)?'':'hidden';
}
}
function SgConfirmPassBeforeSave(c1,c2,c3){
if(document.getElementById('setPassRow'))document.getElementById('setPassRow').style.display=c1?'':'none';
if(document.getElementById('fsPassRow'))document.getElementById('fsPassRow').style.display=c2?'':'none';
if(document.getElementById('quitPassRow'))document.getElementById('quitPassRow').style.display=c3?'':'none';
if(document.getElementById('setPass'))document.getElementById('setPass').disabled=false;
if(document.getElementById('fsPass'))document.getElementById('fsPass').disabled=false;
if(document.getElementById('quitPass'))document.getElementById('quitPass').disabled=false;
if(document.getElementById('setPass'))document.getElementById('setPass').value='';
if(document.getElementById('fsPass'))document.getElementById('fsPass').value='';
if(document.getElementById('quitPass'))document.getElementById('quitPass').value='';
if(document.getElementById('setPassErr'))document.getElementById('setPassErr').style.display='none';
if(document.getElementById('fsPassErr'))document.getElementById('fsPassErr').style.display='none';
if(document.getElementById('quitPassErr'))document.getElementById('quitPassErr').style.display='none';
if(document.getElementById('confirmPassPanel'))document.getElementById('confirmPassPanel').style.display='flex';
}
function SgConfirmPassOkButton(){
const p1=elementNamed('setPass');
const p2=elementNamed('fsPass');
const p3=elementNamed('quitPass');
const c1=(p1.value && p1.value!='****************' && !p1.dataset.confirmed);
const c2=(p2.value && p2.value!='****************' && !p2.dataset.confirmed);
const c3=(p3.value && p3.value!='****************' && !p3.dataset.confirmed);
const err1=(c1 && p1.value!=document.getElementById('setPass').value);
const err2=(c2 && p2.value!=document.getElementById('fsPass').value);
const err3=(c3 && p3.value!=document.getElementById('quitPass').value);
if(err1)document.getElementById('setPassErr').style.display='';
else if(c1){
document.getElementById('setPass').disabled=true;
document.getElementById('setPassErr').style.display='none';
p1.dataset.confirmed=1;
}
if(err2)document.getElementById('fsPassErr').style.display='';
else if(c2){
document.getElementById('fsPass').disabled=true;
document.getElementById('fsPassErr').style.display='none';
p2.dataset.confirmed=1;
}
if(err3)document.getElementById('quitPassErr').style.display='';
else if(c3){
document.getElementById('quitPass').disabled=true;
document.getElementById('quitPassErr').style.display='none';
p3.dataset.confirmed=1;
}
if(!err1 && !err2 && !err3){
document.getElementById('confirmPassPanel').style.display='none';
SgSave();
}
}
function SgConfirmPassCancelButton(){
document.getElementById('confirmPassPanel').style.display='none';
}
function SgSetUpAudioDeviceMenus(){
let devMenu=elementNamed('audioDevice');
if(!devMenu)return;
let chanMenu=elementNamed('channelConfig');
let rateMenu=elementNamed('sampleRate');
let optionsButton=document.getElementById('audioOptionsButton');
if(!devMenu || !chanMenu || !rateMenu)return;
chanMenu.innerHTML='';
rateMenu.innerHTML='';
chanMenu.disabled=true;
rateMenu.disabled=true;
if(devMenu.selectedIndex<0)return;
if(devMenu.selectedIndex==0){
let opt=AddElement(chanMenu,'option');
opt.textContent='-';
chanMenu.selectedIndex=0;
opt=AddElement(rateMenu,'option');
opt.textContent='-';
rateMenu.selectedIndex=0;
if(optionsButton)optionsButton.disabled=true;
return;
}
let devOpt=devMenu.options[devMenu.selectedIndex];
if(!devOpt.dataset.channels){
let opt=AddElement(chanMenu,'option');
opt.textContent=Loc('Decided By Device');
opt.value=0;
chanMenu.selectedIndex=0;
}else{
for(let i=0;i<devOpt.dataset.channels;i++){
let opt=AddElement(chanMenu,'option');
opt.textContent=Loc('Mono; Channel {0}',i+1);
opt.value=(i+1);
}
if(devOpt.dataset.channels>1)for(let i=0;i<devOpt.dataset.channels;i+=2){
let opt=AddElement(chanMenu,'option');
opt.textContent=Loc('Stereo; Channels {0}+{1}',i+1,i+2);
opt.value=(i+1)+','+(i+2);
}
if(SelectValueIsValid(chanMenu,chanMenu.dataset.current))chanMenu.value=chanMenu.dataset.current;
else chanMenu.selectedIndex=0;
chanMenu.disabled=false;
}
if(!devOpt.dataset.rates){
let opt=AddElement(rateMenu,'option');
opt.textContent=Loc('Decided By Device');
opt.vaue=0;
rateMenu.selectedIndex=0;
}else{
const arr=devOpt.dataset.rates.split(',');
for(let i=0;i<arr.length;i++){
let opt=AddElement(rateMenu,'option');
opt.textContent=parseInt(arr[i])?arr[i]+' Hz':Loc('Auto');
opt.value=arr[i];
}
if(SelectValueIsValid(rateMenu,rateMenu.dataset.current))rateMenu.value=rateMenu.dataset.current;
else rateMenu.selectedIndex=0;
rateMenu.disabled=false;
}
if(optionsButton)optionsButton.disabled=false;
}
function SgInitialiseTriggers(){
document.querySelectorAll('.triggersDiv').forEach(div=>{
div.title=Loc('TriggersInfo');
});
['mc','a'].forEach(prefix=>{
kTriggers.forEach(name=>{
const div=document.getElementById(prefix+name+'Div');
if(!div)return;
div.title=Loc(name+'Tip');
const span=document.createElement('span');
span.className='triggerText';
if(name==='TriggerAudio')span.textContent=Loc('Audio');
else if(name==='TriggerCamP1')span.textContent=Loc('Camera Port 1');
else if(name==='TriggerCamP2')span.textContent=Loc('Camera Port 2');
else if(name==='TriggerCamPir')span.textContent=Loc('Camera PIR');
else if(name==='TriggerCamMd')span.textContent=Loc('Camera MD');
else if(name==='TriggerHome')span.textContent=Loc('Home')+':';
div.insertBefore(span,div.firstChild);
if(name==='TriggerMotion'||name==='TriggerArrives'||name==='TriggerDeparts'){
let gearButton=document.createElement('button');
gearButton.type='button';
gearButton.className='triggerGearBtn';
gearButton.onclick=(e)=>{SgOpenTriggerPopup(e,prefix+name);};
const gearImg=document.createElement('img');
gearImg.src='../img/gear.png';
gearImg.className='invertableImg';
gearButton.appendChild(gearImg);
div.appendChild(gearButton);
}
let xButton=document.createElement('button');
xButton.type='button';
xButton.className='triggerXBtn';
xButton.onclick=()=>SgRemoveTrigger(prefix+name);
const crossImg=document.createElement('img');
crossImg.src='../img/cross.svg';
crossImg.className='invertableImg';
xButton.appendChild(crossImg);
div.appendChild(xButton);
});
const addButton=document.querySelector(`button[onclick="SgAddTrigger(event,'${prefix}')"]`);
if(addButton){
const plusImg=document.createElement('img');
plusImg.src='../img/plus.png';
plusImg.className='invertableImg';
plusImg.width=16;
plusImg.height=16;
addButton.appendChild(plusImg);
}
});
}
function SgShowHideTriggerDivs(){
if(!document.querySelector('.triggerGearBtn'))SgInitialiseTriggers();
['mc','a'].forEach(prefix=>{
kTriggers.forEach(name=>{
if(document.getElementById(prefix+name+'Div')){
document.getElementById(prefix+name+'Div').style.display=document.getElementById(prefix+name).checked?'':'none';
}
SgUpdateTriggerObjectsText(prefix+name);
});
});
}
function SgUpdateTriggerObjectsText(name){
const div=document.getElementById(name+'Div');
if(!div||div.style.display==='none')return;
let action=null;
if(name.endsWith('TriggerMotion'))action='{0} Moves';
else if(name.endsWith('TriggerArrives'))action='{0} Arrives';
else if(name.endsWith('TriggerDeparts'))action='{0} Departs';
else return;
const h=document.getElementById(name+'H').checked;
const v=document.getElementById(name+'V').checked;
const a=document.getElementById(name+'A').checked;
const textSpan=div.querySelector('.triggerText');
let objects=[];
if(h)objects.push(Loc('Human'));
if(v)objects.push(Loc('Vehicle'));
if(a)objects.push(Loc('Animal'));
if(!objects.length && !name.endsWith('TriggerMotion')){
textSpan.textContent=Loc('Invalid - select an object');
}else{
if(!objects.length)objects.push(Loc('Anything'));
textSpan.textContent=Loc(action,objects.join('/'));
}
}
function SgFixPopupPosition(popup){
const rect=popup.getBoundingClientRect();
if(rect.right>window.innerWidth)popup.style.right='0px';
if(rect.bottom>window.innerHeight)popup.style.top=(window.innerHeight-rect.height)+'px';
}
function SgOpenTriggerPopup(event,name){
const popup=document.getElementById('triggerOptionsPopup');
const hostRect=document.getElementById(name+'Div').getBoundingClientRect();
if(popup.style.display=='block' && name==_sg.popupTrigger){
SgCloseTriggerPopup();
return;
}
document.getElementById('triggerPopupH').checked=document.getElementById(name+'H').checked;
document.getElementById('triggerPopupV').checked=document.getElementById(name+'V').checked
document.getElementById('triggerPopupA').checked=document.getElementById(name+'A').checked
popup.style.right=(window.innerWidth-hostRect.right)+'px';
popup.style.top=(hostRect.bottom)+'px';
popup.style.display='block';
SgFixPopupPosition(popup);
_sg.popupTrigger=name;
if(event)event.stopPropagation();
}
function SgCloseTriggerPopup(){
if(document.getElementById('triggerOptionsPopup'))document.getElementById('triggerOptionsPopup').style.display='none';
_sg.popupTrigger=null;
SgCloseShortcutPopup();
}
function SgTriggerPopupEvent(){
if(!_sg.popupTrigger)return;
let h=document.getElementById('triggerPopupH').checked;
let v=document.getElementById('triggerPopupV').checked;
let a=document.getElementById('triggerPopupA').checked;
document.getElementById(_sg.popupTrigger+'H').checked=h;
document.getElementById(_sg.popupTrigger+'V').checked=v;
document.getElementById(_sg.popupTrigger+'A').checked=a;
SgUpdateTriggerObjectsText(_sg.popupTrigger);
}
function SgAddTrigger(event,prefix){
try{
const names=[Loc('Motion Detection'),Loc('Object Arrives'),Loc('Object Departs'),Loc('Audio Detection'),Loc('Camera Port 1'),Loc('Camera Port 2'),Loc('Camera PIR Sensor'),Loc('Camera Motion Detection'),Loc('Home')];
let menu=new PopMenu(event);
for(let i=0;i<kTriggers.length;i++){
let flags=0;
let callback=function(event){
document.getElementById(prefix+kTriggers[i]).checked=true;
if(kTriggers[i]=='TriggerArrives'||kTriggers[i]=='TriggerDeparts')document.getElementById(prefix+kTriggers[i]+'H').checked=true;
SgShowHideTriggerDivs();
if(kTriggers[i]=='TriggerMotion'||kTriggers[i]=='TriggerArrives'||kTriggers[i]=='TriggerDeparts'){
SgOpenTriggerPopup(event,prefix+kTriggers[i]);
}
};
if(kTriggers[i]=='TriggerArrives' && !OSMeetsRequired("10.15"))continue;
if(kTriggers[i]=='TriggerDeparts' && !OSMeetsRequired("10.15"))continue;
if(elementNamed('deviceType')&& elementNamed('deviceType').value==kDeviceTypeNetwork){
const profile=elementNamed('profile');
const opt=profile.options[profile.selectedIndex];
const arrData=opt.id.split(',');
flags=parseInt(arrData[5]);
}
if(kTriggers[i]=='TriggerHome'){
if(!elementNamed(prefix+'TriggerHomeId').options.length)callback=null;
}else if(kTriggers[i]=='TriggerCamP1' && !(flags&(1<<0))){
continue;
}else if(kTriggers[i]=='TriggerCamP2' && !(flags&(1<<1))){
continue;
}else if(kTriggers[i]=='TriggerCamPir' && !(flags&(1<<2))){
continue;
}else if(kTriggers[i]=='TriggerCamMd' && !(flags&(1<<3))){
continue;
}
menu.addItem(names[i],false,document.getElementById(prefix+kTriggers[i]).checked?null:callback);
}
}catch(error){}
}
function SgRemoveTrigger(name){
document.getElementById(name+'Div').style.display='none';
document.getElementById(name).checked=false;
if(document.getElementById(name+'H'))document.getElementById(name+'H').checked=false;
if(document.getElementById(name+'V'))document.getElementById(name+'V').checked=false;
if(document.getElementById(name+'A'))document.getElementById(name+'A').checked=false;
}
const kGeoContinents=['XF','XA','XE','XM','XO','XS'];
const kGeoCountries=['AD','AE','AF','AG','AI','AL','AM','AO','AR','AS','AT','AU','AW','AX','AZ','BA','BB','BD','BE','BF','BG','BH','BI','BJ','BL','BM','BN','BO','BQ','BR','BS','BT','BW','BY','BZ','CA','CD','CF','CG','CH','CI','CL','CM','CN','CO','CR','CU','CV','CW','CY','CZ','DE','DJ','DK','DM','DO','DZ','EC','EE','EG','ER','ES','ET','FI','FJ','FK','FM','FO','FR','GA','GB','GD','GE','GF','GG','GH','GI','GL','GM','GN','GP','GQ','GR','GT','GU','GW','GY','HK','HN','HR','HT','HU','ID','IE','IL','IM','IN','IQ','IR','IS','IT','JE','JM','JO','JP','KE','KG','KH','KI','KM','KN','KP','KR','KW','KY','KZ','LA','LB','LC','LI','LK','LR','LS','LT','LU','LV','LY','MA','MC','MD','ME','MF','MG','MH','MK','ML','MM','MN','MO','MP','MQ','MR','MS','MT','MU','MV','MW','MX','MY','MZ','NA','NC','NE','NF','NG','NI','NL','NO','NP','NR','NU','NZ','OM','PA','PE','PF','PG','PH','PK','PL','PM','PR','PS','PT','PW','PY','QA','RE','RO','RS','RU','RW','SA','SB','SC','SD','SE','SG','SH','SI','SK','SL','SM','SN','SO','SR','SS','ST','SV','SX','SY','SZ','TC','TD','TG','TH','TJ','TK','TL','TM','TN','TO','TR','TT','TV','TW','TZ','UA','UG','US','UY','UZ','VC','VE','VG','VI','VN','VU','WF','WS','XK','YE','YT','ZA','ZM','ZW'];
function SgInitGeoblock(){
const div=document.getElementById('geoblockDiv');
if(!div)return;
const list=document.getElementById('geoblockList').value;
for(let i=0;i+1<list.length;i+=2)SgAddGeoblockPill(list.substring(i,i+2));
const addBtn=document.getElementById('geoblockAddBtn');
if(addBtn && !addBtn.querySelector('img')){
const img=document.createElement('img');
img.src='../img/plus.png';
img.className='invertableImg';
img.width=16;
img.height=16;
addBtn.appendChild(img);
}
SgGeoblockTypeChange();
}
function SgGeoblockTypeChange(){
const btn=document.getElementById('geoblockAddBtn');
if(btn)btn.disabled=document.getElementById('geoblockType').value==='0';
}
function SgAddGeoblockPill(code){
const div=document.getElementById('geoblockDiv');
const pill=document.createElement('div');
pill.dataset.code=code;
const span=document.createElement('span');
span.className='triggerText';
span.textContent=LocGeo(code);
pill.appendChild(span);
const xBtn=document.createElement('button');
xBtn.type='button';
xBtn.className='triggerXBtn';
xBtn.onclick=()=>{pill.remove();SgUpdateGeoblockList();};
const crossImg=document.createElement('img');
crossImg.src='../img/cross.svg';
crossImg.className='invertableImg';
xBtn.appendChild(crossImg);
pill.appendChild(xBtn);
div.appendChild(pill);
}
function SgUpdateGeoblockList(){
let list='';
document.querySelectorAll('#geoblockDiv > div').forEach(d=>{list+=d.dataset.code;});
document.getElementById('geoblockList').value=list;
}
function SgAddGeoblock(event){
try{
const menu=new PopMenu(event,true);
menu.addSectionTitle(Loc('Continents'));
kGeoContinents.forEach(code=>{
const exists=document.querySelector('#geoblockDiv > div[data-code="'+code+'"]');
menu.addItem(LocGeo(code),false,exists?null:()=>{SgAddGeoblockPill(code);SgUpdateGeoblockList();});
});
menu.addSectionTitle(Loc('Countries'));
kGeoCountries.forEach(code=>{
const exists=document.querySelector('#geoblockDiv > div[data-code="'+code+'"]');
menu.addItem(LocGeo(code),false,exists?null:()=>{SgAddGeoblockPill(code);SgUpdateGeoblockList();});
});
menu.addSectionTitle(Loc('Options'));
menu.addItem(Loc('Remove All Locations'),false,()=>{document.getElementById('geoblockDiv').innerHTML='';SgUpdateGeoblockList();});
}catch(e){}
}
function SgInitialiseShortcuts(){
const btn=document.getElementById('addShortcutButton');
if(!btn)return;
const plusImg=document.createElement('img');
plusImg.src='../img/plus.png';
plusImg.className='invertableImg';
plusImg.width=16;
plusImg.height=16;
btn.appendChild(plusImg);
}
function SgShowHideShortcutDivs(){
const container=document.getElementById('shortcutsDiv');
if(!container)return;
if(!document.getElementById('addShortcutButton').querySelector('img'))SgInitialiseShortcuts();
container.innerHTML='';
const homeList=document.getElementById('homeActionsList');
for(let i=0;i<8;i++){
const el=document.querySelector('input[name="homeShortcut'+i+'"]');
if(!el||!el.value)continue;
const id=parseInt(el.value);
if(!id)continue;
let name='';
if(homeList){
const opt=homeList.querySelector('option[value="'+id+'"]');
if(opt)name=opt.textContent;
}
if(!name)continue;
const div=document.createElement('div');
div.id='homeActionDiv'+i;
const span=document.createElement('span');
span.className='triggerText';
span.textContent=name;
div.appendChild(span);
const xBtn=document.createElement('button');
xBtn.type='button';
xBtn.className='triggerXBtn';
xBtn.onclick=function(){SgRemoveHomeShortcut(i);};
const xImg=document.createElement('img');
xImg.src='../img/cross.svg';
xImg.className='invertableImg';
xBtn.appendChild(xImg);
div.appendChild(xBtn);
container.appendChild(div);
}
for(let i=0;i<4;i++){
const nameEl=document.querySelector('input[name="cmdName'+i+'"]');
const urlEl=document.querySelector('input[name="cmd'+i+'"]');
if(!nameEl||!urlEl)continue;
const name=nameEl.value;
const url=urlEl.value;
if(name||url){
const div=document.createElement('div');
div.id='urlShortcutDiv'+i;
const span=document.createElement('span');
span.className='triggerText';
span.textContent=name||Loc('Shortcut {0}',i+1);
div.appendChild(span);
const gearBtn=document.createElement('button');
gearBtn.type='button';
gearBtn.className='triggerGearBtn';
gearBtn.onclick=function(e){SgOpenShortcutPopup(e,i);};
const gearImg=document.createElement('img');
gearImg.src='../img/gear.png';
gearImg.className='invertableImg';
gearBtn.appendChild(gearImg);
div.appendChild(gearBtn);
const xBtn=document.createElement('button');
xBtn.type='button';
xBtn.className='triggerXBtn';
xBtn.onclick=function(){SgRemoveShellShortcut(i);};
const xImg=document.createElement('img');
xImg.src='../img/cross.svg';
xImg.className='invertableImg';
xBtn.appendChild(xImg);
div.appendChild(xBtn);
container.appendChild(div);
}
}
}
function SgGetActiveHomeShortcutIds(){
const ids=[];
for(let i=0;i<8;i++){
const el=document.querySelector('input[name="homeShortcut'+i+'"]');
if(el&&el.value&&el.value!=='0')ids.push(parseInt(el.value));
}
return ids;
}
function SgAddShortcut(event){
event.preventDefault();
let menu=new PopMenu(event);
const homeList=document.getElementById('homeActionsList');
const activeIds=SgGetActiveHomeShortcutIds();
if(homeList){
const opts=homeList.querySelectorAll('option');
opts.forEach(opt=>{
const id=parseInt(opt.value);
const inUse=activeIds.includes(id);
menu.addItem(opt.textContent,false,inUse?null:function(){SgAddHomeShortcut(id);});
});
}
let shellCount=0;
for(let i=0;i<4;i++){
const nameEl=document.querySelector('input[name="cmdName'+i+'"]');
const cmdEl=document.querySelector('input[name="cmd'+i+'"]');
if(nameEl&&cmdEl&&(nameEl.value||cmdEl.value))shellCount++;
}
menu.addItem(Loc('Shell Command or URL'),false,(shellCount>=4)?null:function(e){
for(let i=0;i<4;i++){
const nameEl=document.querySelector('input[name="cmdName'+i+'"]');
const cmdEl=document.querySelector('input[name="cmd'+i+'"]');
if(nameEl&&cmdEl&&!nameEl.value&&!cmdEl.value){
nameEl.value=Loc('Shortcut {0}',i+1);
SgShowHideShortcutDivs();
SgOpenShortcutPopup(e,i);
break;
}
}
});
}
function SgAddHomeShortcut(id){
for(let i=0;i<8;i++){
const el=document.querySelector('input[name="homeShortcut'+i+'"]');
if(el&&(!el.value||el.value==='0')){
el.value=id;
SgShowHideShortcutDivs();
return;
}
}
}
function SgRemoveHomeShortcut(index){
const el=document.querySelector('input[name="homeShortcut'+index+'"]');
if(el)el.value='0';
SgShowHideShortcutDivs();
}
function SgOpenShortcutPopup(event,index){
const popup=document.getElementById('shortcutOptionsPopup');
if(!popup)return;
const btn=document.getElementById('addShortcutButton');
const rect=btn.getBoundingClientRect();
popup.style.right=(window.innerWidth-rect.right)+'px';
popup.style.top=rect.bottom+'px';
popup.style.display='block';
SgFixPopupPosition(popup);
document.getElementById('shortcutName').value=document.querySelector('input[name="cmdName'+index+'"]').value||Loc('Shortcut {0}',index+1);
document.getElementById('shortcutCmd').value=document.querySelector('input[name="cmd'+index+'"]').value;
_sg.shortcutIndex=index;
if(event)event.stopPropagation();
}
function SgCloseShortcutPopup(){
const popup=document.getElementById('shortcutOptionsPopup');
if(!popup||popup.style.display!='block')return;
const i=_sg.shortcutIndex;
let name=document.getElementById('shortcutName').value.trim();
if(!name)name=Loc('Shortcut {0}',i+1);
document.querySelector('input[name="cmdName'+i+'"]').value=name;
document.querySelector('input[name="cmd'+i+'"]').value=document.getElementById('shortcutCmd').value;
popup.style.display='none';
_sg.shortcutIndex=null;
SgShowHideShortcutDivs();
}
function SgRemoveShellShortcut(index){
document.querySelector('input[name="cmdName'+index+'"]').value='';
document.querySelector('input[name="cmd'+index+'"]').value='';
SgShowHideShortcutDivs();
}
function SgOrderlyClose(){
if(_sg.formData && _sg.formData!=SgCurrentFormData()){
let alert=new Alert(Loc('save_changes'));
alert.addButton(Loc('Save'),async function(){
await SgSave();
window.webkit.messageHandlers.jsHandler.postMessage('close');
});
alert.addButton(Loc("Don't Save"),function(){
window.webkit.messageHandlers.jsHandler.postMessage('close');
});
}else{
window.webkit.messageHandlers.jsHandler.postMessage('close');
}
}
function SgConfigureHome(val){
if(val==2)fetch('openHomeHelper',{credentials:'same-origin'});
else if(val==1){
let alert=new Alert(Loc('home_info_1'));
alert.addButton(Loc('View in App Store…'),async function(){
fetch('openUrl?url='+encodeURIComponent('itms-apps://apps.apple.com/app/homehelper/id1536545668'),{credentials:'same-origin'});
});
alert.addButton(Loc('Cancel'),null);
}else{
SimpleAlert(Loc('home_info_2'));
}
}
function SgShowImageSharePanel(){
SgImageShareSetupCheckboxes();
if(document.getElementById('imageShare').checked)document.getElementById('imageSharePanel').style.display='flex';
}
function SgImageShareOkButton(){
document.getElementById('imageSharePanel').style.display='none';
}
function SgImageShareCancelButton(){
document.getElementById('imageShare').checked=false;
document.getElementById('imageSharePanel').style.display='none';
}
function SgImageShareSetupCheckboxes(){
let disabled=document.getElementById('shareSelected').checked?false:true;
const boxes=document.getElementById('shareCams').querySelectorAll('input[type="checkbox"]');
for(box of boxes)box.disabled=disabled;
}
function SgActionSoundChanged(which){
if(document.getElementById('soundButton'+which)&& elementNamed('aSound'+which))document.getElementById('soundButton'+which).disabled=(elementNamed('aSound'+which).disabled || !elementNamed('aSound'+which).value)?true:false;
}
async function SgPlaySound(which){
let soundName=elementNamed('aSound'+which).value;
let soundSpeaker=document.getElementById('soundSpeaker'+which);
let soundSpinner=document.getElementById('soundSpinner'+which);
let audioBuffer=null;
if(!soundName || soundSpeaker.dataset.playing)return;
if(!_sg.audioContext)_sg.audioContext=new(window.AudioContext || window.webkitAudioContext)();
if(_sg.audioContext){
soundSpeaker.style.display='none';
soundSpinner.style.display='block';
try{
let result=await fetch('soundFile?format=m4a&name='+encodeURIComponent(soundName),{credentials:'same-origin'});
if(!result.ok)throw new Error(`HTTP ${result.status}: ${result.statusText}`);
let arrayBuffer=await result.arrayBuffer();
audioBuffer = await new Promise((resolve,reject)=>{
_sg.audioContext.decodeAudioData(arrayBuffer,resolve,reject);
});
}catch(error){
console.error('Error downloading or decoding audio:',error);
}
soundSpeaker.style.display='block';
soundSpinner.style.display='none';
}
if(audioBuffer){
const source=_sg.audioContext.createBufferSource();
source.buffer=audioBuffer;
source.connect(_sg.audioContext.destination);
function handleEnd(){
soundSpeaker.src='../img/speaker-off.png';
soundSpeaker.dataset.playing="";
}
source.addEventListener('ended',handleEnd);
source.start(_sg.audioContext.currentTime);
source.stop(_sg.audioContext.currentTime+10);
soundSpeaker.dataset.playing="1";
soundSpeaker.src='../img/speaker-on.png';
}else{
soundSpeaker.src='../img/speaker-no.png';
}
}
function SgShellExamples(event){
try{
const array=[
{name:'HTTP GET',command:'curl -X GET http://address/path'},
{name:'HTTP POST Without Parameters',command:'curl -X POST http://address/path'},
{name:'HTTP POST With Parameters',command:'curl -X POST -d "param1=value1&param2=value2" http://address/path'},
{name:'IFTTT Trigger',command:'curl -X POST https://maker.ifttt.com/trigger/EVENT/with/key/MYKEY'},
{name:Loc('Say Something'),command:'say "intruder alert"'},
{name:Loc('Run Shortcut'),command:'shortcuts run "shortcut name"'},
{name:Loc('Run Bash Script File'),command:'/Path/To/Script.sh'}];
let menu=new PopMenu(event);
menu.addSectionTitle(Loc('Examples'));
array.forEach(function(item){
menu.addItem(item.name,false,function(){
elementNamed('aShellCommand').value=item.command;
});
});
menu.addSectionTitle(Loc('Test'));
menu.addItem(Loc('Test Current Command'),false,function(){
SgTestShellCommand();
});
}catch(error){}
}
async function SgTestShellCommand(){
let cmd=elementNamed('aShellCommand').value;
if(!cmd)return;
let panel=document.getElementById('testShellCommandPanel');
let output=document.getElementById('shellTestOutput');
let spinner=document.getElementById('shellTestSpinner');
output.textContent=Loc('Running command…');
spinner.style.display='';
panel.style.display='flex';
try{
let result=await fetch('doShell?command='+encodeURIComponent(cmd),{credentials:'same-origin'});
let txt=await result.text();
output.textContent=txt||Loc('(No output)');
}catch(error){
output.textContent=String(error);
}
spinner.style.display='none';
}
async function SgLicenseRefresh(event){
let feedback=document.getElementById('licenseRefreshFeedback');
let submitButton=document.getElementById('licenseSubmit');
let refreshButton=document.getElementById('licenseRefresh');
let refreshButtonName=refreshButton.textContent;
refreshButton.innerHTML='<img src="../img/spinner.png" class="spinner" width="14" height="14" style="display:inline;">';
refreshButton.disabled=true;
submitButton.disabled=true;
let result=await fetch('refreshLicenseInfo'+(event.altKey?'?alt=1':''),{credentials:'same-origin'});
if(_sg.which!='license')return;
if(result.status==200){
const response=await result.json();
if(_sg.which!='license')return;
if(response.err){
feedback.innerHTML=Loc('Error {0} {1}',response.err,response.errDesc);
refreshButton.textContent=refreshButtonName;
refreshButton.disabled=false;
submitButton.disabled=false;
}else{
SgFetchPage(event);
}
}else{
feedback.innerHTML=Loc('Request failed with status {0}',result.status);
refreshButton.textContent=refreshButtonName;
refreshButton.disabled=false;
submitButton.disabled=false;
}
}
async function SgHandleLicenseFile(event){
let file=event.target.files[0];
if(file){
let formData=new FormData();
formData.append('file',file);
let response=await fetch('submitLicenseFile',{credentials:'same-origin',method:'POST',body:formData});
if(_sg.which!='license')return;
if(response.ok){
let data=await response.json();
if(_sg.which!='license')return;
if(data.result=='OK')SgFetchPage(null,'didSubmit=1');
else document.getElementById('licenseFeedback').textContent=data.msg;
}else{
document.getElementById('licenseFeedback').textContent=Loc('Bad server response {0}',response.status);
}
}
};
async function SgLicenseSubmit(event){
if(event.altKey){
let input=AddElement(document.body,'input');
input.addEventListener('change',SgHandleLicenseFile,false);
input.type='file';
input.multiple=false;
input.webkitdirectory=false;
input.click();
}else{
const nameInput=document.getElementById('licenseName');
const codeInput=document.getElementById('licenseCode');
const feedback=document.getElementById('licenseFeedback');
if(!nameInput.value){feedback.textContent=Loc('Please enter your license name');return;}
if(!codeInput.value){feedback.textContent=Loc('Please enter your license code');return;}
feedback.textContent='';
document.getElementById('licenseSubmit').innerHTML='<img src="../img/spinner.png" class="spinner" width="14" height="14" style="display:inline;">';
document.getElementById('licenseSubmit').disabled=true;
document.getElementById('licenseRefresh').disabled=true;
await fetch('submitLicenseInfo?wait=1&name='+encodeURIComponent(nameInput.value)+'&code='+encodeURIComponent(codeInput.value),{credentials:'same-origin'});
if(_sg.which=='license')SgFetchPage(null,'didSubmit=1');
}
}
async function SgLicenseClear(){
if(document.getElementById('storeFeedback'))document.getElementById('storeFeedback').textContent='';
await fetch('submitLicenseInfo',{credentials:'same-origin'});
if(_sg.which=='license')SgFetchPage();
}
function SgPurchase(){
const currencySymbols=['$','&pound;','&euro;'];
const input=SelectedRadioByName('prod');
if(!input)return;
let html=Loc('purchase_1',input.dataset.name,currencySymbols[input.dataset.currency],input.dataset.price);
html+=Loc(parseInt(input.dataset.upgrade)?'purchase_2':'purchase_3');
html+=Loc('purchase_4')+'<br>&nbsp;';
document.getElementById('purchaseInfo').innerHTML='<p>'+html+'</p>';
document.getElementById('storeName').disabled=parseInt(input.dataset.upgrade)?true:false;
document.getElementById('storeFeedback').textContent='';
document.getElementById('buyPanel').style.display='flex';
}
async function SgPurchaseContinue(){
const name=document.getElementById('storeName').value;
const email=document.getElementById('storeEmail').value;
const mailingList=document.getElementById('mailingList').checked?1:0;
const code=document.getElementById('storeCode').value;
const oldIntCode=document.getElementById('storeOldIntCode').value;
const feedback=document.getElementById('storeFeedback');
let storeUrl='https://store.bensoftware.com';
if(name.length<1){feedback.textContent=Loc('Please enter a name');return;}
else if(name.length<3){feedback.textContent=Loc('Please enter a longer name');return;}
if(!IsValidEmail(email)){feedback.textContent=Loc('Please enter a valid email address');return;}
const input=SelectedRadioByName('prod');
if(!input)return;
document.getElementById('storePurchase').innerHTML='<img src="../img/spinner.png" class="spinner" width="14" height="14" style="display:inline;">';
document.getElementById('storePurchase').disabled=true;
const postBody='name='+encodeURIComponent(name)+'&code='+code+'&oldIntCode='+oldIntCode+'&email='+email+'&productNum='+input.value+'&currency='+input.dataset.currency+'&upgrade='+input.dataset.upgrade+'&mailingList='+mailingList+trackingParams();
try{
let result=await fetch(storeUrl+'/store-order',{
credentials:'same-origin',
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:postBody
});
if(!result.ok){
const errorMessage=`HTTP status ${result.status}`;
const errorText=await result.text();
throw new Error(`${errorMessage}\n${errorText}`);
}
let json=await result.json();
if(json.message){
feedback.textContent=json.message;
}else{
OpenUrlInNewTab(storeUrl+'/store-pay?orderId='+json.orderId);
fetch('submitLicenseInfo?poll=1&name='+encodeURIComponent(json.name)+'&code='+json.code+'&email='+json.email+'&upgrade='+input.dataset.upgrade,{credentials:'same-origin'});
document.getElementById('buyPanel').style.display='none';
}
}catch(error){
console.log(error);
feedback.textContent=Loc('Error submitting store request: {0}',error);
}
document.getElementById('storePurchase').innerHTML=Loc('Purchase');
document.getElementById('storePurchase').disabled=false;
}
function SgOfferVersions(latest,offerV5Flag){
if(document.getElementById('versSelect')){
SgDoUpdate(parseInt(document.getElementById('versSelect').value));
}else{
let sel=document.createElement('select');
let targetDiv=document.getElementById('updateInfoDiv');
let updateButton=document.getElementById('updateButton');
sel.className='widthF';
sel.id='versSelect';
let opt=document.createElement('option');
opt.value=kVLatestBeta;
opt.textContent=Loc('Latest Beta Version');
sel.appendChild(opt);
for(let v=latest;v>0 && v>latest-5;v--){
opt=document.createElement('option');
opt.value=v;
opt.textContent=Loc('Version {0}','6.'+v);
sel.appendChild(opt);
}
if(offerV5Flag){
document.createElement('option');
opt.value=kV5Reversion;
opt.textContent=Loc('Version {0}','5.5.11');
sel.appendChild(opt);
}
targetDiv.insertBefore(sel,updateButton);
updateButton.textContent=Loc('Install');
}
}
function SgUpdate(version){
if(version==kV5Reversion){
let alert=new Alert(Loc('revert_v5_1'),Loc('revert_v5_2'));
alert.addButton(Loc('Revert'),function(){SgDoUpdate(version)});
alert.addButton(Loc('Cancel'),null);
}else{
SgDoUpdate(version);
}
}
function SgDoUpdate(version){
fetch('updateStart?version='+version,{credentials:'same-origin'});
_sg.updateVersion=version;
_sg.updateButtonName=document.getElementById('updateButton').innerHTML;
document.getElementById('updateProgress').value=0;
document.getElementById('updateCancel').style.display='inline';
document.getElementById('updateButton').innerHTML=Loc('Downloading…');
document.getElementById('updateButton').disabled=true;
document.getElementById('updateFeedback').innerHTML='';
document.getElementById('updateProgressDiv').style.display='block';
_sg.updateTimer=setTimeout(SgGetUpdateStatus,2000);
}
function SgUpdateCancel(){
fetch('updateCancel',{credentials:'same-origin'});
document.getElementById('updateProgressDiv').style.display='none';
document.getElementById('updateButton').innerHTML=_sg.updateButtonName;
document.getElementById('updateButton').disabled=false;
if(_sg.updateTimer){clearTimeout(_sg.updateTimer);_sg.updateTimer=null;}
}
async function SgGetUpdateStatus(){
_sg.updateTimer=null;
if(!document.getElementById('updateProgress'))return;
try{
let result=await fetch('updateStatus',{credentials:'same-origin'});
if(result.status==200){
const response=await result.json();
let progress=document.getElementById('updateProgress');
if(progress){
if(response.active){
progress.value=response.percentDownloaded;
if(response.percentDownloaded==100){
document.getElementById('updateButton').innerHTML=Loc('Installing…');
document.getElementById('updateCancel').display='none';
}
_sg.updateTimer=setTimeout(SgGetUpdateStatus,1000);
}else{
if(response.err){
document.getElementById('updateProgressDiv').style.display='none';
document.getElementById('updateFeedback').innerHTML=Loc('Error {0} {1}',response.err,response.errDesc);
document.getElementById('updateButton').innerHTML=_sg.updateButtonName;
document.getElementById('updateButton').disabled=false;
}else{
window.location='/';
}
}
}
}
else if(_sg.updateVersion==kV5Reversion)window.location='/';
}catch(error){
if(_sg.which=='license'){
_sg.updateTimer=setTimeout(SgGetUpdateStatus,2000);
}
}
}
async function SgAddAllServerCams(){
let addr=document.getElementById('sssAddress').value;
let port=document.getElementById('sssPort').value;
let user=encodeURIComponent(document.getElementById('sssUsername').value);
let pass=encodeURIComponent(document.getElementById('sssPassword').value);
let fps=document.getElementById('sssFps').value;
let format=document.getElementById('sssFormat').value;
let ssl=document.getElementById('sssSsl').checked?1:0;
let permissive=document.getElementById('sssPermissive').checked?1:0;
let feedback=document.getElementById('sssFeedback');
let cancelButton=document.getElementById('sssCancelButton');
let okButton=document.getElementById('sssOkButton');
let okButtonName=okButton.innerHTML;
if(!addr){feedback.innerHTML=Loc('Please enter the address of the server');return;}
okButton.innerHTML='<img src="../img/spinner.png" class="spinner" width="14" height="14" style="display:inline;">';
okButton.disabled=true;
cancelButton.disabled=true;
try{
let result=await fetch('addAllServerCams?addr='+addr+'&port='+port+'&user='+user+'&pass='+pass+'&fps='+fps+'&format='+format+'&ssl='+ssl+'&permissive='+permissive,{credentials:'same-origin'});
if(result.status==200){
const response=await result.json();
okButton.innerHTML=okButtonName;
okButton.disabled=false;
cancelButton.disabled=false;
if(response.err){
feedback.textContent='Failed with error '+response.err+(response.errDesc?' ('+response.errDesc+')':'');
}else{
if(response.cams && response.cams.length){
let prevIndex=_sg.camMenu.selectedIndex();
for(cam of response.cams)_sg.camMenu.addOption(cam.name,cam.num);
if(prevIndex<0){
_sg.camMenu.selectIndex(0);
if(_sg.which=='cameras')SgFetchPage();
}
}
document.getElementById('sssPanel').style.display='none';
}
}else{
feedback.innerHTML='Request failed with status '+result.status;
okButton.innerHTML=okButtonName;
okButton.disabled=false;
cancelButton.disabled=false;
}
}catch(error){
feedback.textContent=error;
okButton.textContent=Loc('OK');
okButton.disabled=false;
cancelButton.disabled=false;
}
}
async function SgAddNVRCams(){
let addr=document.getElementById('nvrAddress').value;
let port=document.getElementById('nvrPort').value;
let user=encodeURIComponent(document.getElementById('nvrUsername').value);
let pass=encodeURIComponent(document.getElementById('nvrPassword').value);
let profile=encodeURIComponent(document.getElementById('nvrProfile').value);
let count=encodeURIComponent(document.getElementById('nvrCount').value);
let feedback=document.getElementById('nvrFeedback');
let cancelButton=document.getElementById('nvrCancelButton');
let okButton=document.getElementById('nvrOkButton');
let okButtonName=okButton.innerHTML;
if(!addr){feedback.textContent=Loc('Please enter the address of the NVR');return;}
okButton.innerHTML='<img src="../img/spinner.png" class="spinner" width="14" height="14" style="display:inline;">';
okButton.disabled=true;
cancelButton.disabled=true;
try{
let result=await fetch('addNVRCams?addr='+addr+'&port='+port+'&user='+user+'&pass='+pass+'&profile='+profile+'&count='+count,{credentials:'same-origin'});
if(result.status==200){
const response=await result.json();
okButton.innerHTML=okButtonName;
okButton.disabled=false;
cancelButton.disabled=false;
if(response.err){
feedback.innerHTML=Loc('Error {0} {1}',response.err,response.errDesc);
}else{
if(response.cams && response.cams.length){
let prevIndex=_sg.camMenu.selectedIndex();
for(cam of response.cams)_sg.camMenu.addOption(cam.name,cam.num);
if(prevIndex<0){
_sg.camMenu.selectIndex(0);
if(_sg.which=='cameras')SgFetchPage();
}
}
document.getElementById('nvrPanel').style.display='none';
}
}else{
feedback.innerHTML=Loc('Request failed with status {0}',result.status);
okButton.innerHTML=okButtonName;
okButton.disabled=false;
cancelButton.disabled=false;
}
}catch(error){
feedback.innerHTML=error;
okButton.innerHTML=Loc('OK');
okButton.disabled=false;
cancelButton.disabled=false;
}
}
function SgHowHidePass(button){
let field=elementNamed('password');
if(!field)field=document.getElementById('password');
if(!field)return;
if(field.type=='password'){
field.type='text';
button.textContent=Loc('Hide');
}else{
field.type='password';
button.textContent=Loc('Reveal');
}
}
function SgGetAccessInfo(){
fetch('settings-web-access-info',{credentials:'same-origin'})
.then(response =>{
if(!response.ok)throw new Error(Loc('Bad response from server'));
return response.text();
})
.then(html =>{
document.getElementById('accessInfoUrls').innerHTML=html;
document.getElementById('accessInfoPanel').style.display='flex';
})
.catch(error =>{
document.getElementById('accessInfoUrls').innerHTML=Loc('Bad server response {0}',error);
document.getElementById('accessInfoPanel').style.display='flex';
});
}
function SgShowMaskPanel(which){
let div=document.getElementById('previewImageDiv0');
let camNum=parseInt(elementNamed('cameraNum').value);
div.style.width='800px';
div.style.height='500px';
div.style.marginBottom="8px";
_sg.whichPanelMask=which;
document.getElementById('maskPanel').style.display='flex';
if(which==1){
_sg.maskPicker0=new MaskPicker(div,camNum,_sg.maskPicker1.maskStr(),'rgba(0,0,0,1)',100);
}else{
_sg.maskPicker0=new MaskPicker(div,camNum,_sg.maskPicker2.maskStr(),'rgba(0,180,0,1)',70);
_sg.maskPicker0.cropSource=_sg.maskPicker1;
}
_sg.maskPicker1.pause();
_sg.maskPicker2.pause();
_sg.maskPicker3.pause();
}
function SgCloseMaskPanel(save){
if(save){
if(_sg.whichPanelMask==1)_sg.maskPicker1.drawMaskStr(_sg.maskPicker0.maskStr());
else _sg.maskPicker2.drawMaskStr(_sg.maskPicker0.maskStr());
}
_sg.maskPicker0.dispose();
_sg.maskPicker0=null;
_sg.maskPicker1.resume();
_sg.maskPicker2.resume();
_sg.maskPicker3.resume();
document.getElementById('maskPanel').style.display='none';
}
function SgSliderSetup(){
let array=['brightness','contrast','fisheyeStrength','motionSensitivity','audioSensitivity','humanSensitivity','vehicleSensitivity','animalSensitivity','audioDeviceVol'];
array.forEach(function(item){
let slider=elementNamed(item);
let text=document.getElementById(item+'Text');
if(slider && text)text.textContent=slider.value;
});
let fisheyeType=elementNamed('fisheyeType');
let fisheyeStrength=elementNamed('fisheyeStrength');
if(fisheyeType && fisheyeStrength){
fisheyeStrength.disabled=parseInt(fisheyeType.value)?false:true;
}
}
