/* Pi-hole: A black hole for Internet advertisements * (c) 2017 Pi-hole, LLC (https://pi-hole.net) * Network-wide ad blocking via your own hardware. * * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ /* global utils:false, groups:false, apiFailure:false, updateFtlInfo:false, getGroups:false, processGroupResult:false */ /* exported initTable */ var table; var GETDict = {}; $(function () { GETDict = utils.parseQueryString(); $("#btnAddAllow").on("click", { type: "allow" }, addList); $("#btnAddBlock").on("click", { type: "block" }, addList); utils.setBsSelectDefaults(); getGroups(); }); function format(data) { // Generate human-friendly status string var statusText = "Unknown"; var numbers = true; if (data.status !== null) { switch (parseInt(data.status, 10)) { case 0: statusText = data.enabled === 0 ? "List is disabled and not checked" : "List was not downloaded so far"; numbers = false; break; case 1: statusText = 'List download was successful (OK)'; break; case 2: statusText = 'List unchanged upstream, Pi-hole used a local copy (OK)'; break; case 3: statusText = 'List unavailable, Pi-hole used a local copy (check list)'; break; case 4: statusText = 'List unavailable, there is no local copy of this list available on your Pi-hole (replace list)'; numbers = false; break; default: statusText = 'Unknown (' + parseInt(data.status, 10) + ")"; break; } } // Compile extra info for displaying return ( "" + '" + "
Type of this list:' + data.type + 'list
Health status of this list:' + statusText + '
This list was added to Pi-hole  ' + utils.datetimeRelative(data.date_added) + " (" + utils.datetime(data.date_added, false) + ')
Database entry was last modified  ' + utils.datetimeRelative(data.date_modified) + " (" + utils.datetime(data.date_modified, false) + ')
The list contents were last updated  ' + (data.date_updated > 0 ? utils.datetimeRelative(data.date_updated) + " (" + utils.datetime(data.date_updated, false) + ")" : "N/A") + '
Number of entries on this list:  ' + (data.number !== null && numbers === true ? parseInt(data.number, 10).toLocaleString() : "N/A") + (data.abp_entries !== null && parseInt(data.abp_entries, 10) > 0 && numbers === true ? " (out of which " + parseInt(data.abp_entries, 10).toLocaleString() + " are in ABP-style)" : "") + '
Number of non-domains on this list:  " + (data.invalid_domains !== null && numbers === true ? parseInt(data.invalid_domains, 10).toLocaleString() : "N/A") + '
Database ID of this list:' + data.id + "
" ); } // eslint-disable-next-line no-unused-vars function initTable() { table = $("#listsTable").DataTable({ processing: true, ajax: { url: "/api/lists", dataSrc: "lists", type: "GET", }, order: [[0, "asc"]], columns: [ { data: "id", visible: false }, { data: null, visible: true, orderable: false, width: "15px" }, { data: "status", searchable: false, class: "details-control" }, { data: "address" }, { data: "enabled", searchable: false }, { data: "comment" }, { data: "groups", searchable: false }, { data: null, width: "22px", orderable: false }, ], columnDefs: [ { targets: 1, className: "select-checkbox", render: function () { return ""; }, }, { targets: "_all", render: $.fn.dataTable.render.text(), }, ], drawCallback: function () { // Hide buttons if all lists were deleted var hasRows = this.api().rows({ filter: "applied" }).data().length > 0; $(".datatable-bt").css("visibility", hasRows ? "visible" : "hidden"); $('button[id^="deleteList_"]').on("click", deleteList); // Remove visible dropdown to prevent orphaning $("body > .bootstrap-select.dropdown").remove(); }, rowCallback: function (row, data) { var dataId = utils.hexEncode(data.address); $(row).attr("data-id", dataId); $(row).attr("data-type", data.type); var statusCode = 0, statusIcon; // If there is no status or the list is disabled, we keep // status 0 (== unknown) if (data.status !== null && data.enabled) { statusCode = parseInt(data.status, 10); } switch (statusCode) { case 1: statusIcon = "fa-check"; break; case 2: statusIcon = "fa-history"; break; case 3: statusIcon = "fa-exclamation-circle"; break; case 4: statusIcon = "fa-times"; break; default: statusIcon = "fa-question-circle"; break; } // Add red minus sign icon if data["type"] is "block" // Add green plus sign icon if data["type"] is "allow" let status = ""; if (data.type === "block") { status = ""; } else if (data.type === "allow") { status = ""; } $("td:eq(1)", row).addClass("list-status-" + statusCode); $("td:eq(1)", row).html( "" + status ); if (data.address.startsWith("file://")) { // Local files cannot be downloaded from a distant client so don't show // a link to such a list here $("td:eq(2)", row).html( '' + data.address + "" ); } else { $("td:eq(2)", row).html( '' + data.address + "" ); } $("td:eq(3)", row).html( '" ); var statusEl = $("#enabled_" + dataId, row); statusEl.bootstrapToggle({ on: "Enabled", off: "Disabled", size: "small", onstyle: "success", width: "80px", }); statusEl.on("change", editList); $("td:eq(4)", row).html(''); var commentEl = $("#comment_" + dataId, row); commentEl.val(utils.unescapeHtml(data.comment)); commentEl.on("change", editList); $("td:eq(5)", row).empty(); $("td:eq(5)", row).append( '' ); var selectEl = $("#multiselect_" + dataId, row); // Add all known groups for (var i = 0; i < groups.length; i++) { var dataSub = ""; if (!groups[i].enabled) { dataSub = 'data-subtext="(disabled)"'; } selectEl.append( $("