// 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");