// Constants
const SUPER_ADMIN_ROLE = 1;
const DATALOGGER_TYPE = 1;
const PHOTOTRAPPING_TYPE = 2;
const DATALOGGER_PHOTO_TYPE = 3;
const CUSTOMER_UNASSIGNED = 1;
const LOCATION_WAREHOUSE = 1;
const BROKER_DEFAULT = 1;
const REPORT_DETAILED_ID = 1;
const REPORT_SUMMARY_ID = 2;
const DATAFRAME_DEFAULT = 1;
// BULK ACTIONS
const ASSIGN_GROUPS = 1;
const APPLY_DATALOGGER_TEMPLATE = 2;
const CHANGE_RESEARCH_TEAM = 3;
const CHANGE_DATAFRAME = 4;
let STYLE;
let sActionButtons = '';
$(document).ready(() => {
STYLE = getComputedStyle(document.body);
$('.menu-desktop a').click(function () {
let start = '';
if (location.pathname == '/index.php' || location.pathname.split('/').length == 2) {
start = './';
} else {
for (let i = 0; i < location.pathname.split('/').length - 2; i++) {
start += '../';
}
start += './';
}
const enlace = this;
if ($(enlace).data("url") != undefined && $(enlace).data("url") != "") {
const datosTracker = {};
const urlAccess = start + "app/backend/ajax.php?module=horizontal_active&id=" + $(enlace).data("id");
callWebservice(urlAccess, "get", datosTracker, (response) => {
location.href = start + $(enlace).data("url");
});
} else {
location.href = $(enlace).attr("href");
}
});
});
function replaceUrlParam(url, paramName, paramValue) {
if (paramValue == null) {
paramValue = '';
}
let pattern = new RegExp('\\b(' + paramName + '=).*?(&|#|$)');
if (url.search(pattern) >= 0) {
return url.replace(pattern, '$1' + paramValue + '$2');
}
url = url.replace(/[?#]$/, '');
return url + (url.indexOf('?') > 0 ? '&' : '?') + paramName + '=' + paramValue;
}
function setCookie(name, value, days) {
let expires = "";
if (days) {
let date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
let nameEQ = name + "=";
let ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function eraseCookie(name) {
document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
function getContrastYIQ(hexcolor) {
hexcolor = hexcolor.replace("#", "");
let r = parseInt(hexcolor.substr(0, 2), 16);
let g = parseInt(hexcolor.substr(2, 2), 16);
let b = parseInt(hexcolor.substr(4, 2), 16);
let yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
return (yiq >= 128) ? 'black' : 'white';
}
const callWebservice = (url, type, datos, callBack) => {
let options = {
url: url,
type: type,
data: datos
};
$.ajax(options)
.done(function (response, textStatus, xhr) {
callBack(response, textStatus, xhr);
})
.fail(function (xhr, textStatus, errorThrown) {
console.log(errorThrown);
callBack(errorThrown, textStatus, xhr);
})
.always(function () {
});
};
function initTable(module, aColumns, callback, role = null, baseUrl = null) {
if (baseUrl == undefined) {
baseUrl = "backend/";
}
const table = $('#tabla').DataTable({
deferRender: true,
autoWidth: true,
scrollY: ((module == 'iot_devices') ? ((role == 1) ? 'calc(100vh - 410px)' : 'calc(100vh - 320px)') : 'calc(100vh - 300px)'),
scrollX: '50vh',
scroller: {
rowHeight: 41,
loadingIndicator: true,
},
stateSave: true,
"order": [],
"ajax": {
"url": "./app/backend/ajax.php?module=" + module + "_list",
"dataSrc": ""
},
"initComplete": function (settings, json) {
if (callback != undefined) {
const tableTemp = settings.oInstance.api();
callback(tableTemp);
}
$('table.dataTable td, table.dataTable th').css('font-size', '0.875rem');
},
columns: aColumns
}).on("draw", () => {
initTableButtons(module, baseUrl);
});
return table;
}
// Función genérica de filtrado de tablas
const selectFields = ['countries', 'iot_types', 'groups', 'lw_device_locations', 'roles'];
function initTableFilters(fields, tableTemp, filter_size = 12, col_size = 4, callback) {
// Reset every filter
tableTemp.columns().search('').draw();
// Add the filters and its events
if (fields.length == 1) {
const filterHtml = `
Clear Filters
`;
$('input[type=search]').addClass('field_filter');
$('input[type=search]').attr('data-id', '0');
$('#tabla_filter').append(filterHtml);
$('.clear_filters').click(function () {
$('.field_filter[type=search]').val('').keyup();
});
$('.field_filter[type=search]').keyup(function () {
if ($(this).val() != "") {
tableTemp.column(parseInt($(this).data('id'))).search($(this).val()).draw();
} else {
tableTemp.column(parseInt($(this).data('id'))).search('').draw();
}
});
if (callback) {
callback();
}
} else {
let filterHtml = `
Clear Filters
Filter Data
`;
$('#tabla_filter').parents('.row:first').addClass('justify-content-between');
$('#tabla_filter').parent().removeClass('col-md-6').addClass('col-md-auto align-self-end');
$('#tabla_filter').html(filterHtml);
$('#tabla_filter').parents('.row:first').after(`
`);
$('.filter_list').hide();
initTableFiltersRec(fields, 0, tableTemp, col_size, callback);
}
}
function initTableFiltersRec(fields, index, tableTemp, col_size, callback) {
if (index < fields.length) {
const title = $(tableTemp.column(index).header()).text();
let filterHtml = ``;
if (selectFields.includes(fields[index])) {
const urlData = `./app/backend/ajax.php?module=${fields[index]}_list`;
callWebservice(urlData, "post", {}, (response) => {
const elements = JSON.parse(response);
filterHtml += `
`;
$('#tabla_wrapper .filter_list').append(filterHtml);
initTableFiltersRec(fields, index + 1, tableTemp, col_size, callback);
});
} else if (fields[index] == 'is_active') {
filterHtml += ``;
$('#tabla_wrapper .filter_list').append(filterHtml);
initTableFiltersRec(fields, index + 1, tableTemp, col_size, callback);
} else if (fields[index] != 'id') {
filterHtml += ``;
$('#tabla_wrapper .filter_list').append(filterHtml);
initTableFiltersRec(fields, index + 1, tableTemp, col_size, callback);
} else {
initTableFiltersRec(fields, index + 1, tableTemp, col_size, callback);
}
} else {
// Finished adding the filters, now add the events
$('.activate_filters').click(function () {
if ($('.filter_list').is(':visible')) {
$('.filter_list').hide();
$('.activate_filters i').removeClass('fa-minus').addClass('fa-plus');
} else {
$('.filter_list').show();
$('.activate_filters i').removeClass('fa-plus').addClass('fa-minus');
}
});
$('.clear_filters').click(function () {
$('.field_filter[type=text]').val('').keyup();
$('select.field_filter').val('').change();
tableTemp.columns().search('').draw();
});
$('.field_filter[type=text]').keyup(function () {
if ($(this).val() != "") {
tableTemp.column(parseInt($(this).data('id'))).search($(this).val()).draw();
} else {
tableTemp.column(parseInt($(this).data('id'))).search('').draw();
}
});
$('select.field_filter').change(function () {
if ($(this).val() != "") {
tableTemp.column(parseInt($(this).data('id'))).search('^' + $(this).val() + '$', true, false, false).draw();
} else {
$('#tabla').DataTable().column($(this).data('id')).search('').draw();
}
});
if (callback) {
callback();
}
}
}
function initTableButtons(module, baseUrl) {
if (baseUrl == undefined) {
baseUrl = "backend/";
}
$('.action-edit').unbind('click').click(function () {
let id = $(this).parent().parent().find('input#id').val();
if (baseUrl == "backend/") {
location.href = module + "/" + id;
} else {
location.href = "index.php?app=" + baseUrl + module + "_edit&id=" + id;
}
});
$('.action-delete').unbind('click').click(function () {
let id = $(this).parent().parent().find('input#id').val();
Swal.fire({
title: 'Do you want to delete the element? ',
text: 'The change cannot be reversed. ',
icon: 'error',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Delete',
cancelButtonText: 'Cancel'
}).then((result) => {
if (result.isConfirmed) {
if (baseUrl == "backend/") {
location.href = module + "/delete/" + id;
} else {
location.href = "index.php?app=" + baseUrl + module + "_delete&id=" + id;
}
}
});
});
$('#tabla tbody tr').dblclick(function (e) {
if ($(e.target).is(':not(input[type=checkbox])')) {
$(this).find('.action-edit').click();
}
});
}
function castVersionToCode(version) {
const aVersion = version.split('.');
let code = 0;
if (aVersion.length > 0) {
code = 1000000 * parseInt(aVersion[0]) + 1000 * parseInt(aVersion[1]) + parseInt(aVersion[2]);
}
return code;
};
//Función generica de guardado de formulario
function initForm(urlBack) {
$('.form-save').click(function () {
if (validate("datos")) {
$('form#datos').submit();
}
});
$('.form-cancel').click(function () {
location.href = urlBack;
});
}
function redirect(urlBack) {
location.href = urlBack;
}
function validate(form) {
form = form.replace("#", "");
form = document.getElementById(form);
let pristine = new Pristine(form);
let valid = pristine.validate();
return valid;
}
// Restricts input for the set of matched elements to the given inputFilter function.
(function ($) {
$.fn.inputFilter = function (inputFilter) {
return this.on("input keydown keyup mousedown mouseup select contextmenu drop", function () {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
} else if (this.hasOwnProperty("oldValue")) {
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
} else {
this.value = "";
}
});
};
}(jQuery));
function durationToMilli(time, unit) {
let time_milli = 0;
switch (unit) {
case 'ms':
time_milli = time;
break;
case 's':
time_milli = time * 1000;
break;
case 'm':
time_milli = time * 60000;
break;
case 'h':
time_milli = time * 3600000;
break;
case 'd':
time_milli = time * 86400000;
break;
default:
break;
}
return time_milli;
}
function updateDeviceInformation(device_id, deviceData) {
// Update device firmware version
if ("version" in deviceData && deviceData.version != null) {
const data = {
device_id: device_id,
version: deviceData.version
};
const urlData = "/app/backend/ajax.php?module=change_firmware_version"
callWebservice(urlData, "POST", data, () => {});
}
// Update device active
if ("mode" in deviceData && deviceData.mode != null) {
const dataActive = {
device_id: device_id,
active: (deviceData.mode == 'active') ? 1: 0
};
const urlDataActive = "/app/backend/ajax.php?module=set_device_active"
callWebservice(urlDataActive, "POST", dataActive, () => {});
}
// Update device location
if ("fixed_pos" in deviceData && deviceData.fixed_pos != null) {
const dataPos = {
device_id: device_id,
lat: deviceData.fixed_pos.split(', ')[0],
lon: deviceData.fixed_pos.split(', ')[1]
};
if (parseFloat(dataPos.lat) == 0 || parseFloat(dataPos.lon) == 0) {
dataPos.lat = null;
dataPos.lon = null;
}
const urlDataPos = "/app/backend/ajax.php?module=set_device_position"
callWebservice(urlDataPos, "POST", dataPos, () => {});
}
// Update device ICCID
if ("iccid" in deviceData && deviceData.iccid != null) {
const dataICCID = {
device_id: device_id,
iccid: deviceData.iccid
};
const urlDataICCID = "/app/backend/ajax.php?module=set_device_iccid"
callWebservice(urlDataICCID, "POST", dataICCID, () => {});
}
// Update device MAC
if ("ble_mac" in deviceData && deviceData.ble_mac != null) {
const dataMAC = {
device_id: device_id,
ble_mac: deviceData.ble_mac
};
const urlDataMAC = "/app/backend/ajax.php?module=set_device_mac"
callWebservice(urlDataMAC, "POST", dataMAC, () => {});
}
}
// Pristine Custom Validators
Pristine.addValidator('my-number', function (value) {
if (value != "") {
const aux = value.replace(/\s/g, '');
return aux != "" && !(isNaN(aux));
} else {
return true;
}
}, "This field must contain a number");
Pristine.addValidator('my-integer', function (value) {
if (value != "") {
const aux = value.replace(/\s/g, '');
return aux != "" && !(isNaN(aux)) && Number.isInteger(parseFloat(aux));
} else {
return true;
}
}, "This field must contain an integer");
Pristine.addValidator("my-range", function (value, min, max) {
if (value != "") {
return parseFloat(value) >= min && parseFloat(value) <= max;
} else {
return true;
}
}, "The value (${0}) must be between ${1} and ${2}");
Pristine.addValidator('pos-number', function (value) {
if (value != "") {
const aux = value.replace(/\s/g, '');
return aux != "" && !(isNaN(aux)) && parseFloat(aux) > 0;
} else {
return true;
}
}, "This field must contain a positive number");
Pristine.addValidator('pos-integer', function (value) {
if (value != "") {
const aux = value.replace(/\s/g, '');
return aux != "" && !(isNaN(aux)) && parseFloat(aux) > 0 && Number.isInteger(parseFloat(aux));
} else {
return true;
}
}, "This field must contain a positive integer");
Pristine.addValidator('nat-integer', function (value) {
if (value != "") {
const aux = value.replace(/\s/g, '');
return aux != "" && !(isNaN(aux)) && parseFloat(aux) >= 0 && Number.isInteger(parseFloat(aux));
} else {
return true;
}
}, "This field must contain a non-negative integer");
Pristine.addValidator("my-time-range", function (value, min, max) {
if (value != "") {
const unit = $(this).parent().parent().find('select').val();
const valueMilli = durationToMilli(parseFloat(value), unit);
return valueMilli >= min && valueMilli <= max;
} else {
return true;
}
}, "The time value must be between ${1}ms and ${2}ms");
Pristine.addValidator('ble-per-adv', function (value) {
if (value != "") {
return parseFloat(value) >= 20 && parseFloat(value) <= 10240;
} else {
return true;
}
}, "This field must be in the range [20, 10240]");
Pristine.addValidator('my-hour', function (value) {
if (value != "") {
return /^([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/.test(value);
} else {
return true;
}
}, "This input has to be a time");
Pristine.addValidator('ordered-hours', function (value) {
const tab = $(this).parents('.hours_list:first');
const hours = tab.find('input[id^="rec_hour"]').map(function () {
const h = this.value.split(':');
return parseInt(h[0]) * 3600 + parseInt(h[1]) * 60 + parseInt(h[2]);
}).get();
let sorted = true;
let i = 0;
while (sorted && i < hours.length - 1) {
if (hours[i] >= hours[i + 1]) {
sorted = false;
}
i++;
}
return sorted;
}, "The hours must be defined in chronological order");
Pristine.addValidator('unique-hours', function (value) {
const tab = $(this).parents('.hours_list:first');
const hours = tab.find('input[id^="rec_hour"]').map(function () {
const h = this.value.split(':');
return parseInt(h[0]) * 3600 + parseInt(h[1]) * 60 + parseInt(h[2]);
}).get();
return (new Set(hours)).size == hours.length;
}, "The hours cannot be repeated");
Pristine.addValidator('measures', function (value) {
return $('#sensor_config .active_measures_div input[type=checkbox]:checked').length > 0;
}, "There has to be at least one measure enabled");
Pristine.addValidator('input-ain', function (value) {
return !usedAinPorts.includes(parseInt(value));
}, "There can only be one sensor on each port");
Pristine.addValidator('input-din', function (value) {
return !usedDinPorts.includes(parseInt(value));
}, "There can only be one sensor on each port");
Pristine.addValidator('input-address', function (value) {
return !usedAddress.includes(parseInt(value));
}, "The address is already in use");
Pristine.addValidator('input-rs', function (value) {
return !usedModbus.includes(parseInt(value));
}, "The address is already in use");
Pristine.addValidator('rsregister', function (value) {
return parseInt(value) >= 0 && parseInt(value) <= 65535;
}, "The register must be an integer in the range [0, 65535]");
Pristine.addValidator('rsvalue', function (value) {
let res = false;
switch ($('input[name=rs_reg_type]:checked').val()) {
case 'C':
case 'DI':
res = /\b[01]{1}\b/.test(value);
break;
case 'HR':
case 'IR':
res = /\b[0-9A-Fa-f]{4}\b/.test(value);
break;
}
return res;
}, "Invalid Value");
Pristine.addValidator('rsnbytes', function (value) {
return [2, 4, 8].includes(parseInt(value));
}, "The number of bytes can only be 2, 4 o 8");
Pristine.addValidator('batt', function () {
if ($('#batt_min').val() != '' && $('#batt_max').val() != '') {
return parseFloat($('#batt_min').val()) < parseFloat($('#batt_max').val());
} else {
return true;
}
}, "The lower threshold must be smaller than the upper threshold");
Pristine.addValidator('my-number-formula', function (value) {
let valid = true;
const tab = $(this).parents('.measure-tab');
if (tab.find('[id*=formula_type]').val() == "linear") {
const aux = value.replace(/\s/g, '');
valid = valid && aux != "" && !(isNaN(aux));
}
return valid;
}, "This field must contain a number");
// Checks that each parameter is not empty and it's a number
Pristine.addValidator('linear-number', function (value) {
let valid = true;
const tab = $(this).parents('.measure-tab');
if (tab.find('[id*=formula_type]').val() == "linear") {
valid = valid && tab.find('[id*=linear-param] input:enabled').map(function () { return this.value; }).get().every((v) => {
const aux = v.replace(/\s/g, '');
return aux != "" && !(isNaN(aux));
});
}
return valid;
}, "Every parameter must be a number");
// Checks that the parameters are in order
Pristine.addValidator('linear-x', function (value) {
let valid = true;
const tab = $(this).parents('.measure-tab');
if (tab.find('[id*=formula_type] option:selected').val() == "linear") {
const intV = tab.find('[id*=linear-param] input[name*="x"]:enabled').map(function () { return parseFloat(this.value) }).get();
let sorted = true;
let i = 0;
while (sorted && i < intV.length - 1) {
if (intV[i] >= intV[i + 1]) {
sorted = false;
}
i++;
}
valid = valid && sorted;
}
return valid;
}, "The input parameters must be in order");
// Checks if the power supply times are defined in the case that the option selected is interval
Pristine.addValidator('supply', function (value) {
if ($('input[name=power_supply_time]:checked').val() == 'interval') {
const aux = value.replace(/\s/g, '');
return aux != "" && !(isNaN(aux)) && parseFloat(aux) >= 0 && Number.isInteger(parseFloat(aux));
} else {
return true;
}
}, "This field must contain a positive integer");
// Checks if the field is not an empty string or just whitespaces
Pristine.addValidator('my-required', function (value) {
return value.replace(/\s/g, '') != '';
}, "This field is required");
// Checks if the field does not start with _ or digit and doesnt have spaces
Pristine.addValidator('dataframe', function (value) {
return value == "" || (/^(\S+)(\w)$/.test(value) && value.charAt(0) != '_' && isNaN(value.charAt(0)));
}, "This field cannot contain whitespaces or special characters and it cannot start with underscore or digits");