mirror of
https://github.com/pi-hole/web.git
synced 2024-12-06 19:36:21 +01:00
Merge branch 'devel' into TopItems
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
// User menu toggle
|
||||
$("#dropdown-menu a").on("click", function(event) {
|
||||
$(this).parent().toggleClass("open");
|
||||
});
|
||||
$("body").on("click", function(event) {
|
||||
if(!$("#dropdown-menu").is(event.target) && $("#dropdown-menu").has(event.target).length === 0) {
|
||||
$("#dropdown-menu").removeClass("open");
|
||||
}
|
||||
});
|
||||
|
||||
function piholeChanged(action)
|
||||
{
|
||||
const status = $("#status");
|
||||
const ena = $("#pihole-enable");
|
||||
const dis = $("#pihole-disable");
|
||||
|
||||
switch(action) {
|
||||
case "enabled":
|
||||
status.html("<i class='fa fa-circle' style='color:#7FFF00'></i> Active");
|
||||
ena.hide();
|
||||
dis.show();
|
||||
dis.removeClass("active");
|
||||
break;
|
||||
|
||||
case "disabled":
|
||||
status.html("<i class='fa fa-circle' style='color:#FF0000'></i> Offline");
|
||||
ena.show();
|
||||
dis.hide();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function piholeChange(action, duration)
|
||||
{
|
||||
const token = encodeURIComponent($("#token").html());
|
||||
var btnStatus;
|
||||
|
||||
switch(action) {
|
||||
case "enable":
|
||||
btnStatus = $("#flip-status-enable");
|
||||
btnStatus.html("<i class='fa fa-spinner'> </i>");
|
||||
$.getJSON("api.php?enable&token=" + token, (data) => {
|
||||
if(data.status === "enabled") {
|
||||
btnStatus.html("");
|
||||
piholeChanged("enabled");
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "disable":
|
||||
btnStatus = $("#flip-status-disable");
|
||||
btnStatus.html("<i class='fa fa-spinner'> </i>");
|
||||
$.getJSON("api.php?disable=" + duration + "&token=" + token, (data) => {
|
||||
if(data.status === "disabled") {
|
||||
btnStatus.html("");
|
||||
piholeChanged("disabled");
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Enable/Disable
|
||||
$("#pihole-enable").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
piholeChange("enable","");
|
||||
});
|
||||
$("#pihole-disable-permanently").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
piholeChange("disable","0");
|
||||
});
|
||||
$("#pihole-disable-10s").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
piholeChange("disable","10");
|
||||
setTimeout(function(){piholeChanged("enabled");},10000);
|
||||
});
|
||||
$("#pihole-disable-30s").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
piholeChange("disable","30");
|
||||
setTimeout(function(){piholeChanged("enabled");},30000);
|
||||
});
|
||||
$("#pihole-disable-5m").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
piholeChange("disable","300");
|
||||
setTimeout(function(){piholeChanged("enabled");},300000);
|
||||
});
|
||||
|
||||
var piholeVersion = $("#piholeVersion").html();
|
||||
var webVersion = $("#webVersion").html();
|
||||
|
||||
// Credit for following function: https://gist.github.com/alexey-bass/1115557
|
||||
// Modified to discard any possible "v" in the string
|
||||
function versionCompare(left, right) {
|
||||
if (typeof left + typeof right !== "stringstring")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are on vDev then we assume that it is always
|
||||
// newer than the latest online release, i.e. version
|
||||
// comparison should return 1
|
||||
if(left === "vDev")
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var aa = left.split("v"),
|
||||
bb = right.split("v");
|
||||
|
||||
var a = aa[aa.length-1].split(".")
|
||||
, b = bb[bb.length-1].split(".")
|
||||
, i = 0, len = Math.max(a.length, b.length);
|
||||
|
||||
for (; i < len; i++) {
|
||||
if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
|
||||
return 1;
|
||||
} else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Update check
|
||||
$.getJSON("https://api.github.com/repos/pi-hole/pi-hole/releases/latest", function(json) {
|
||||
if(versionCompare(piholeVersion, json.tag_name.slice(1)) < 0) {
|
||||
// Alert user
|
||||
$("#piholeVersion").html($("#piholeVersion").text() + "<a class=\"alert-link\" href=\"https://github.com/pi-hole/pi-hole/releases\">(Update available!)</a>");
|
||||
$("#alPiholeUpdate").show();
|
||||
}
|
||||
});
|
||||
$.getJSON("https://api.github.com/repos/pi-hole/AdminLTE/releases/latest", function(json) {
|
||||
if(versionCompare(webVersion, json.tag_name.slice(1)) < 0) {
|
||||
// Alert user
|
||||
$("#webVersion").html($("#webVersion").text() + "<a class=\"alert-link\" href=\"https://github.com/pi-hole/adminLTE/releases\">(Update available!)</a>");
|
||||
$("#alWebUpdate").show();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Make sure that Pi-hole is updated to at least v2.7, since that is needed to use the sudo
|
||||
* features of the interface. Skip if on dev
|
||||
*/
|
||||
if(versionCompare(piholeVersion, "v2.7") < 0) {
|
||||
alert("Pi-hole needs to be updated to at least v2.7 before you can use features such as whitelisting/blacklisting from this web interface!");
|
||||
}
|
||||
|
||||
// Session timer
|
||||
var sessionvalidity = parseInt(document.getElementById("sessiontimercounter").textContent);
|
||||
var start = new Date;
|
||||
|
||||
function updateSessionTimer()
|
||||
{
|
||||
start = new Date;
|
||||
start.setSeconds(start.getSeconds() + sessionvalidity);
|
||||
}
|
||||
|
||||
if(sessionvalidity > 0)
|
||||
{
|
||||
// setSeconds will correctly handle wrap-around cases
|
||||
updateSessionTimer();
|
||||
|
||||
setInterval(function() {
|
||||
var current = new Date;
|
||||
var totalseconds = (start - current) / 1000;
|
||||
|
||||
// var hours = Math.floor(totalseconds / 3600);
|
||||
// totalseconds = totalseconds % 3600;
|
||||
|
||||
var minutes = Math.floor(totalseconds / 60);
|
||||
if(minutes < 10){ minutes = "0" + minutes; }
|
||||
|
||||
var seconds = Math.floor(totalseconds % 60);
|
||||
if(seconds < 10){ seconds = "0" + seconds; }
|
||||
|
||||
if(totalseconds > 0)
|
||||
{
|
||||
document.getElementById("sessiontimercounter").textContent = minutes + ":" + seconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById("sessiontimercounter").textContent = "-- : --";
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById("sessiontimer").style.display = "none";
|
||||
}
|
||||
|
||||
// Hide "exact match" button on queryads.php page if version is 2.9.5 or lower
|
||||
if(versionCompare(piholeVersion, "v2.9.5") < 1)
|
||||
{
|
||||
$("#btnSearchExact").hide();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
function eventsource() {
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var ta = $("#output");
|
||||
var source = new EventSource("scripts/pi-hole/php/gravity.sh.php");
|
||||
|
||||
ta.html("");
|
||||
ta.show();
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
|
||||
source.addEventListener("message", function(e) {
|
||||
if(e.data.indexOf("Pi-hole blocking is") !== -1)
|
||||
{
|
||||
alSuccess.show();
|
||||
}
|
||||
|
||||
ta.append(e.data);
|
||||
|
||||
}, false);
|
||||
|
||||
// Will be called when script has finished
|
||||
source.addEventListener("error", function(e) {
|
||||
alInfo.delay(1000).fadeOut(2000, function() { alInfo.hide(); });
|
||||
source.close();
|
||||
$("#gravityBtn").removeAttr("disabled");
|
||||
}, false);
|
||||
}
|
||||
|
||||
$("#gravityBtn").on("click", () => {
|
||||
$("#gravityBtn").attr("disabled", true);
|
||||
eventsource();
|
||||
});
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
// Remove JS warning
|
||||
var jswarn = document.getElementById("js-warn-exit");
|
||||
jswarn.parentNode.removeChild(jswarn);
|
||||
@@ -0,0 +1,410 @@
|
||||
// Define global variables
|
||||
var timeLineChart, queryTypeChart, forwardDestinationChart;
|
||||
|
||||
function padNumber(num) {
|
||||
return ("00" + num).substr(-2,2);
|
||||
}
|
||||
|
||||
// Helper function needed for converting the Objects to Arrays
|
||||
|
||||
function objectToArray(p){
|
||||
var keys = Object.keys(p);
|
||||
keys.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
|
||||
var arr = [], idx = [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
arr.push(p[keys[i]]);
|
||||
idx.push(keys[i]);
|
||||
}
|
||||
return [idx,arr];
|
||||
}
|
||||
|
||||
// Functions to update data in page
|
||||
|
||||
|
||||
function updateSummaryData(runOnce) {
|
||||
var setTimer = function(timeInSeconds) {
|
||||
if (!runOnce) {
|
||||
setTimeout(updateSummaryData, timeInSeconds * 1000);
|
||||
}
|
||||
};
|
||||
$.getJSON("api.php?summary", function LoadSummaryData(data) {
|
||||
|
||||
["ads_blocked_today", "dns_queries_today", "ads_percentage_today"].forEach(function(today) {
|
||||
var todayElement = $("h3#" + today);
|
||||
todayElement.text() !== data[today] && todayElement.addClass("glow");
|
||||
});
|
||||
|
||||
window.setTimeout(function() {
|
||||
["ads_blocked_today", "dns_queries_today", "domains_being_blocked", "ads_percentage_today"].forEach(function(header, idx) {
|
||||
var textData = idx === 3 ? data[header] + "%" : data[header];
|
||||
$("h3#" + header).text(textData);
|
||||
});
|
||||
$("h3.statistic.glow").removeClass("glow");
|
||||
}, 500);
|
||||
|
||||
updateSessionTimer();
|
||||
}).done(function() {
|
||||
setTimer(10);
|
||||
}).fail(function() {
|
||||
setTimer(300);
|
||||
});
|
||||
}
|
||||
|
||||
var failures = 0;
|
||||
function updateQueriesOverTime() {
|
||||
$.getJSON("api.php?overTimeData10mins", function(data) {
|
||||
// convert received objects to arrays
|
||||
data.domains_over_time = objectToArray(data.domains_over_time);
|
||||
data.ads_over_time = objectToArray(data.ads_over_time);
|
||||
// remove last data point since it not representative
|
||||
data.ads_over_time[0].splice(-1,1);
|
||||
// Remove possibly already existing data
|
||||
timeLineChart.data.labels = [];
|
||||
timeLineChart.data.datasets[0].data = [];
|
||||
timeLineChart.data.datasets[1].data = [];
|
||||
// Add data for each hour that is available
|
||||
for (var hour in data.ads_over_time[0]) {
|
||||
if ({}.hasOwnProperty.call(data.ads_over_time[0], hour)) {
|
||||
var h = parseInt(data.domains_over_time[0][hour]);
|
||||
var d = new Date().setHours(Math.floor(h / 6), 10 * (h % 6), 0, 0);
|
||||
|
||||
timeLineChart.data.labels.push(d);
|
||||
timeLineChart.data.datasets[0].data.push(data.domains_over_time[1][hour]);
|
||||
timeLineChart.data.datasets[1].data.push(data.ads_over_time[1][hour]);
|
||||
}
|
||||
}
|
||||
$("#queries-over-time .overlay").remove();
|
||||
timeLineChart.update();
|
||||
}).done(function() {
|
||||
// Reload graph after 10 minutes
|
||||
failures = 0;
|
||||
setTimeout(updateQueriesOverTime, 600000);
|
||||
}).fail(function() {
|
||||
failures++;
|
||||
if(failures < 5)
|
||||
{
|
||||
// Try again after 1 minute only if this has not failed more
|
||||
// than five times in a row
|
||||
setTimeout(updateQueriesOverTime, 60000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateQueryTypes() {
|
||||
$.getJSON("api.php?getQueryTypes", function(data) {
|
||||
var colors = [];
|
||||
// Get colors from AdminLTE
|
||||
$.each($.AdminLTE.options.colors, function(key, value) { colors.push(value); });
|
||||
var v = [], c = [];
|
||||
// Collect values and colors, immediately push individual labels
|
||||
$.each(data, function(key , value) {
|
||||
v.push(value);
|
||||
c.push(colors.shift());
|
||||
queryTypeChart.data.labels.push(key.substr(6,key.length - 7));
|
||||
});
|
||||
// Build a single dataset with the data to be pushed
|
||||
var dd = {data: v, backgroundColor: c};
|
||||
// and push it at once
|
||||
queryTypeChart.data.datasets.push(dd);
|
||||
$("#query-types .overlay").remove();
|
||||
queryTypeChart.update();
|
||||
queryTypeChart.chart.config.options.cutoutPercentage=30;
|
||||
queryTypeChart.update();
|
||||
});
|
||||
}
|
||||
|
||||
// Credit: http://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406#4835406
|
||||
function escapeHtml(text) {
|
||||
var map = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
"\"": """,
|
||||
"\'": "'"
|
||||
};
|
||||
|
||||
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
|
||||
}
|
||||
|
||||
function updateTopClientsChart() {
|
||||
$.getJSON("api.php?summaryRaw&getQuerySources", function(data) {
|
||||
var clienttable = $("#client-frequency").find("tbody:last");
|
||||
var domain, percentage, domainname;
|
||||
for (domain in data.top_sources) {
|
||||
|
||||
if ({}.hasOwnProperty.call(data.top_sources, domain)){
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
if(domain.indexOf("|") > -1)
|
||||
{
|
||||
domainname = domain.substr(0, domain.indexOf("|"));
|
||||
}
|
||||
else
|
||||
{
|
||||
domainname = domain;
|
||||
}
|
||||
|
||||
var url = "<a href=\"queries.php?client="+domain+"\">"+domainname+"</a>";
|
||||
percentage = data.top_sources[domain] / data.dns_queries_today * 100;
|
||||
clienttable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_sources[domain] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"%\"> <div class=\"progress-bar progress-bar-blue\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$("#client-frequency .overlay").remove();
|
||||
});
|
||||
}
|
||||
|
||||
function updateForwardDestinations() {
|
||||
$.getJSON("api.php?getForwardDestinations", function(data) {
|
||||
var colors = [];
|
||||
// Get colors from AdminLTE
|
||||
$.each($.AdminLTE.options.colors, function(key, value) { colors.push(value); });
|
||||
var v = [], c = [];
|
||||
// Collect values and colors, immediately push individual labels
|
||||
$.each(data, function(key , value) {
|
||||
v.push(value);
|
||||
c.push(colors.shift());
|
||||
if(key.indexOf("|") > -1)
|
||||
{
|
||||
key = key.substr(0, key.indexOf("|"));
|
||||
}
|
||||
forwardDestinationChart.data.labels.push(key);
|
||||
});
|
||||
// Build a single dataset with the data to be pushed
|
||||
var dd = {data: v, backgroundColor: c};
|
||||
// and push it at once
|
||||
forwardDestinationChart.data.datasets.push(dd);
|
||||
$("#forward-destinations .overlay").remove();
|
||||
forwardDestinationChart.update();
|
||||
forwardDestinationChart.chart.config.options.cutoutPercentage=30;
|
||||
forwardDestinationChart.update();
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopLists() {
|
||||
$.getJSON("api.php?summaryRaw&topItems", function(data) {
|
||||
var domaintable = $("#domain-frequency").find("tbody:last");
|
||||
var adtable = $("#ad-frequency").find("tbody:last");
|
||||
var url, domain, percentage;
|
||||
for (domain in data.top_queries) {
|
||||
if ({}.hasOwnProperty.call(data.top_queries,domain)){
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
if(domain !== "pi.hole")
|
||||
{
|
||||
url = "<a href=\"queries.php?domain="+domain+"\">"+domain+"</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
url = domain;
|
||||
}
|
||||
percentage = data.top_queries[domain] / data.dns_queries_today * 100;
|
||||
domaintable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_queries[domain] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"%\"> <div class=\"progress-bar progress-bar-green\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove table if there are no results (e.g. privacy mode enabled)
|
||||
if(jQuery.isEmptyObject(data.top_queries))
|
||||
{
|
||||
$("#domain-frequency").parent().remove();
|
||||
}
|
||||
|
||||
for (domain in data.top_ads) {
|
||||
if ({}.hasOwnProperty.call(data.top_ads,domain)){
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
url = "<a href=\"queries.php?domain="+domain+"\">"+domain+"</a>";
|
||||
percentage = data.top_ads[domain] / data.ads_blocked_today * 100;
|
||||
adtable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_ads[domain] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"%\"> <div class=\"progress-bar progress-bar-yellow\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
}
|
||||
|
||||
$("#domain-frequency .overlay").remove();
|
||||
$("#ad-frequency .overlay").remove();
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
var isMobile = {
|
||||
Windows: function() {
|
||||
return /IEMobile/i.test(navigator.userAgent);
|
||||
},
|
||||
Android: function() {
|
||||
return /Android/i.test(navigator.userAgent);
|
||||
},
|
||||
BlackBerry: function() {
|
||||
return /BlackBerry/i.test(navigator.userAgent);
|
||||
},
|
||||
iOS: function() {
|
||||
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
},
|
||||
any: function() {
|
||||
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
|
||||
}
|
||||
};
|
||||
|
||||
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
|
||||
timeLineChart = new Chart(ctx, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Total DNS Queries",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(220,220,220,0.5)",
|
||||
borderColor: "rgba(0, 166, 90,.8)",
|
||||
pointBorderColor: "rgba(0, 166, 90,.8)",
|
||||
pointRadius: 1,
|
||||
pointHoverRadius: 5,
|
||||
data: [],
|
||||
pointHitRadius: 5,
|
||||
cubicInterpolationMode: "monotone"
|
||||
},
|
||||
{
|
||||
label: "Blocked DNS Queries",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(0,192,239,0.5)",
|
||||
borderColor: "rgba(0,192,239,1)",
|
||||
pointBorderColor: "rgba(0,192,239,1)",
|
||||
pointRadius: 1,
|
||||
pointHoverRadius: 5,
|
||||
data: [],
|
||||
pointHitRadius: 5,
|
||||
cubicInterpolationMode: "monotone"
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
mode: "x-axis",
|
||||
callbacks: {
|
||||
title(tooltipItem, data) {
|
||||
var label = tooltipItem[0].xLabel;
|
||||
var time = label.match(/(\d?\d):?(\d?\d?)/);
|
||||
var h = parseInt(time[1], 10);
|
||||
var m = parseInt(time[2], 10) || 0;
|
||||
var from = padNumber(h)+":"+padNumber(m)+":00";
|
||||
var to = padNumber(h)+":"+padNumber(m+9)+":59";
|
||||
return "Queries from "+from+" to "+to;
|
||||
},
|
||||
label(tooltipItems, data) {
|
||||
if(tooltipItems.datasetIndex === 1)
|
||||
{
|
||||
var percentage = 0.0;
|
||||
var total = parseInt(data.datasets[0].data[tooltipItems.index]);
|
||||
var blocked = parseInt(data.datasets[1].data[tooltipItems.index]);
|
||||
if(total > 0)
|
||||
{
|
||||
percentage = 100.0*blocked/total;
|
||||
}
|
||||
return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel + " (" + percentage.toFixed(1) + "%)";
|
||||
}
|
||||
else
|
||||
{
|
||||
return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
time: {
|
||||
unit: "hour",
|
||||
displayFormats: {
|
||||
hour: "HH:mm"
|
||||
},
|
||||
tooltipFormat: "HH:mm"
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
},
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
});
|
||||
|
||||
// Pull in data via AJAX
|
||||
|
||||
updateSummaryData();
|
||||
|
||||
updateQueriesOverTime();
|
||||
|
||||
// Create / load "Query Types" only if authorized
|
||||
if(document.getElementById("queryTypeChart"))
|
||||
{
|
||||
ctx = document.getElementById("queryTypeChart").getContext("2d");
|
||||
queryTypeChart = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{ data: [] }]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
animation: {
|
||||
duration: 2000
|
||||
},
|
||||
cutoutPercentage: 0
|
||||
}
|
||||
});
|
||||
updateQueryTypes();
|
||||
}
|
||||
|
||||
// Create / load "Forward Destinations" only if authorized
|
||||
if(document.getElementById("forwardDestinationChart"))
|
||||
{
|
||||
ctx = document.getElementById("forwardDestinationChart").getContext("2d");
|
||||
forwardDestinationChart = new Chart(ctx, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{ data: [] }]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
animation: {
|
||||
duration: 2000
|
||||
},
|
||||
cutoutPercentage: 0
|
||||
}
|
||||
});
|
||||
updateForwardDestinations();
|
||||
}
|
||||
|
||||
// Create / load "Top Domains" and "Top Advertisers" only if authorized
|
||||
if(document.getElementById("domain-frequency")
|
||||
&& document.getElementById("ad-frequency"))
|
||||
{
|
||||
updateTopLists();
|
||||
}
|
||||
|
||||
// Create / load "Top Clients" only if authorized
|
||||
if(document.getElementById("client-frequency"))
|
||||
{
|
||||
updateTopClientsChart();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
// IE likes to cache too much :P
|
||||
$.ajaxSetup({cache: false});
|
||||
|
||||
// Get PHP info
|
||||
var token = $("#token").html();
|
||||
var listType = $("#list-type").html();
|
||||
var fullName = listType === "white" ? "Whitelist" : "Blacklist";
|
||||
|
||||
function sub(index, entry) {
|
||||
var domain = $("#"+index);
|
||||
domain.hide("highlight");
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/sub.php",
|
||||
method: "post",
|
||||
data: {"domain":entry, "list":listType, "token":token},
|
||||
success: function(response) {
|
||||
if(response.length !== 0){
|
||||
return;
|
||||
}
|
||||
domain.remove();
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
alert("Failed to remove the domain!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refresh(fade) {
|
||||
var list = $("#list");
|
||||
if(fade) {
|
||||
list.fadeOut(100);
|
||||
}
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/get.php",
|
||||
method: "get",
|
||||
data: {"list":listType},
|
||||
success: function(response) {
|
||||
list.html("");
|
||||
var data = JSON.parse(response);
|
||||
|
||||
if(data.length === 0) {
|
||||
list.html("<div class=\"alert alert-info\" role=\"alert\">Your " + fullName + " is empty!</div>");
|
||||
}
|
||||
else {
|
||||
data.forEach(function (entry, index) {
|
||||
list.append(
|
||||
"<li id=\"" + index + "\" class=\"list-group-item clearfix\">" + entry +
|
||||
"<button class=\"btn btn-danger btn-xs pull-right\" type=\"button\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></button></li>"
|
||||
);
|
||||
|
||||
// Handle button
|
||||
$("#list #"+index+"").on("click", "button", function() {
|
||||
sub(index, entry);
|
||||
});
|
||||
});
|
||||
}
|
||||
list.fadeIn("fast");
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
$("#alFailure").show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = refresh(false);
|
||||
|
||||
function add() {
|
||||
var domain = $("#domain");
|
||||
if(domain.val().length === 0){
|
||||
return;
|
||||
}
|
||||
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain.val(), "list":listType, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("not a valid argument") >= 0 ||
|
||||
response.indexOf("is not a valid domain") >= 0) {
|
||||
alFailure.show();
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
domain.val("");
|
||||
refresh(true);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
alFailure.show();
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle enter button for adding domains
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#domain").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
add();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle buttons
|
||||
$("#btnAdd").on("click", function() {
|
||||
add();
|
||||
});
|
||||
$("#btnRefresh").on("click", function() {
|
||||
refresh(true);
|
||||
});
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
var tableApi;
|
||||
|
||||
function escapeRegex(text) {
|
||||
var map = {
|
||||
"(": "\\(",
|
||||
")": "\\)",
|
||||
".": "\\.",
|
||||
};
|
||||
return text.replace(/[().]/g, function(m) { return map[m]; });
|
||||
}
|
||||
|
||||
function refreshData() {
|
||||
tableApi.ajax.url("api.php?getAllQueries").load();
|
||||
// updateSessionTimer();
|
||||
}
|
||||
|
||||
function add(domain,list) {
|
||||
var token = $("#token").html();
|
||||
var alInfo = $("#alInfo");
|
||||
var alList = $("#alList");
|
||||
var alDomain = $("#alDomain");
|
||||
alDomain.html(domain);
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
|
||||
if(list === "white")
|
||||
{
|
||||
alList.html("Whitelist");
|
||||
}
|
||||
else
|
||||
{
|
||||
alList.html("Blacklist");
|
||||
}
|
||||
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain, "list":list, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("not a valid argument") >= 0 || response.indexOf("is not a valid domain") >= 0)
|
||||
{
|
||||
alFailure.show();
|
||||
alFailure.delay(1000).fadeOut(2000, function() { alFailure.hide(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
alSuccess.show();
|
||||
alSuccess.delay(1000).fadeOut(2000, function() { alSuccess.hide(); });
|
||||
}
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
alList.html("");
|
||||
alDomain.html("");
|
||||
});
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
alFailure.show();
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
alList.html("");
|
||||
alDomain.html("");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
tableApi = $("#all-queries").DataTable( {
|
||||
"rowCallback": function( row, data, index ){
|
||||
if (data[4] === "Pi-holed") {
|
||||
$(row).css("color","red");
|
||||
$("td:eq(5)", row).html( "<button style=\"color:green;\"><i class=\"fa fa-pencil-square-o\"></i> Whitelist</button>" );
|
||||
}
|
||||
else{
|
||||
$(row).css("color","green");
|
||||
$("td:eq(5)", row).html( "<button style=\"color:red;\"><i class=\"fa fa-ban\"></i> Blacklist</button>" );
|
||||
}
|
||||
|
||||
},
|
||||
dom: "<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'tr>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
"ajax": "api.php?getAllQueries",
|
||||
"autoWidth" : false,
|
||||
"order" : [[0, "desc"]],
|
||||
"columns": [
|
||||
{ "width" : "20%", "type": "date" },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "40%" },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "10%" },
|
||||
],
|
||||
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
|
||||
"columnDefs": [ {
|
||||
"targets": -1,
|
||||
"data": null,
|
||||
"defaultContent": ""
|
||||
} ]
|
||||
});
|
||||
$("#all-queries tbody").on( "click", "button", function () {
|
||||
var data = tableApi.row( $(this).parents("tr") ).data();
|
||||
if (data[4] === "Pi-holed")
|
||||
{
|
||||
add(data[2],"white");
|
||||
}
|
||||
else
|
||||
{
|
||||
add(data[2],"black");
|
||||
}
|
||||
} );
|
||||
|
||||
// Do we want to filter queries?
|
||||
var GETDict = {};
|
||||
location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];});
|
||||
if("client" in GETDict)
|
||||
{
|
||||
// Search in third column (zero indexed)
|
||||
// Use regular expression to only show exact matches, i.e.
|
||||
// don't show 192.168.0.100 when searching for 192.168.0.1
|
||||
// true = use regex, false = don't use smart search
|
||||
tableApi.column(3).search("^"+escapeRegex(GETDict["client"])+"$",true,false);
|
||||
}
|
||||
if("domain" in GETDict)
|
||||
{
|
||||
// Search in second column (zero indexed)
|
||||
tableApi.column(2).search("^"+escapeRegex(GETDict["domain"])+"$",true,false);
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
var exact = "";
|
||||
function eventsource() {
|
||||
var ta = $("#output");
|
||||
var domain = $("#domain");
|
||||
var q = $("#quiet");
|
||||
if(domain.val().length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var quiet = false;
|
||||
if(q.val() === "yes")
|
||||
{
|
||||
quiet = true;
|
||||
exact = "exact";
|
||||
}
|
||||
|
||||
var host = window.location.host;
|
||||
var source = new EventSource("http://"+host+"/admin/scripts/pi-hole/php/queryads.php?domain="+domain.val().toLowerCase()+"&"+exact);
|
||||
|
||||
// Reset and show field
|
||||
ta.empty();
|
||||
ta.show();
|
||||
|
||||
source.addEventListener("message", function(e) {
|
||||
if(!quiet)
|
||||
{
|
||||
ta.append(e.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lines = e.data.split("\n");
|
||||
for(var i = 0;i<lines.length;i++)
|
||||
{
|
||||
if(lines[i].indexOf("results") !== -1 && lines[i].indexOf("0 results") === -1)
|
||||
{
|
||||
var shortstring = lines[i].replace("::: /etc/pihole/","");
|
||||
// Remove "(x results)"
|
||||
shortstring = shortstring.replace(/\(.*/,"");
|
||||
ta.append(shortstring+"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Will be called when script has finished
|
||||
source.addEventListener("error", function(e) {
|
||||
source.close();
|
||||
}, false);
|
||||
|
||||
// Reset exact variable
|
||||
exact = "";
|
||||
}
|
||||
|
||||
// Handle enter button
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#domain").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
exact = "";
|
||||
eventsource();
|
||||
}
|
||||
});
|
||||
// Handle button
|
||||
$("#btnSearch").on("click", function() {
|
||||
exact = "";
|
||||
eventsource();
|
||||
});
|
||||
// Handle exact button
|
||||
$("#btnSearchExact").on("click", function() {
|
||||
exact = "exact";
|
||||
eventsource();
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
$(function () {
|
||||
$("[data-mask]").inputmask();
|
||||
});
|
||||
|
||||
$(".confirm-reboot").confirm({
|
||||
text: "Are you sure you want to send a reboot command to your Pi-Hole?",
|
||||
title: "Confirmation required",
|
||||
confirm(button) {
|
||||
$("#rebootform").submit();
|
||||
},
|
||||
cancel(button) {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, reboot",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
|
||||
});
|
||||
|
||||
$(".confirm-restartdns").confirm({
|
||||
text: "Are you sure you want to send a restart command to your DNS server?",
|
||||
title: "Confirmation required",
|
||||
confirm(button) {
|
||||
$("#restartdnsform").submit();
|
||||
},
|
||||
cancel(button) {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, restart DNS",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$(".confirm-flushlogs").confirm({
|
||||
text: "By default, the log is flushed at the end of the day via cron, but a very large log file can slow down the Web interface, so flushing it can be useful. Note that your statistics will be reset and you lose the statistics up to this point. Are you sure you want to flush your logs?",
|
||||
title: "Confirmation required",
|
||||
confirm(button) {
|
||||
$("#flushlogsform").submit();
|
||||
},
|
||||
cancel(button) {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, flush logs",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$("#DHCPchk").click(function() {
|
||||
$("input.DHCPgroup").prop("disabled", !this.checked);
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
if(document.getElementById("DHCPLeasesTable"))
|
||||
{
|
||||
$("#DHCPLeasesTable").DataTable({
|
||||
dom: "<'row'<'col-sm-12'i>>" +
|
||||
"<'row'<'col-sm-12'tr>>" +
|
||||
"<'row'<'col-sm-5'f><'col-sm-7'p>>",
|
||||
"pageLength": 5
|
||||
});
|
||||
}
|
||||
} );
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
var offset, timer, pre, scrolling = true;
|
||||
|
||||
// Check every 200msec for fresh data
|
||||
var interval = 200;
|
||||
|
||||
// Function that asks the API for new data
|
||||
function reloadData(){
|
||||
clearTimeout(timer);
|
||||
$.getJSON("api.php?tailLog="+offset, function (data)
|
||||
{
|
||||
offset = data["offset"];
|
||||
pre.append(data["lines"]);
|
||||
});
|
||||
|
||||
if(scrolling)
|
||||
{
|
||||
window.scrollTo(0,document.body.scrollHeight);
|
||||
}
|
||||
timer = setTimeout(reloadData, interval);
|
||||
}
|
||||
|
||||
$(function(){
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("api.php?tailLog", function (data)
|
||||
{
|
||||
offset = data["offset"];
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
});
|
||||
|
||||
$("#chk1").click(function() {
|
||||
$("#chk2").prop("checked",this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").click(function() {
|
||||
$("#chk1").prop("checked",this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
require('auth.php');
|
||||
|
||||
$type = $_POST['list'];
|
||||
|
||||
// All of the verification for list editing
|
||||
list_verify($type);
|
||||
|
||||
switch($type) {
|
||||
case "white":
|
||||
echo exec("sudo pihole -w -q ${_POST['domain']}");
|
||||
break;
|
||||
case "black":
|
||||
echo exec("sudo pihole -b -q ${_POST['domain']}");
|
||||
break;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
require('func.php');
|
||||
$ERRORLOG = getenv('PHP_ERROR_LOG');
|
||||
if (empty($ERRORLOG)) {
|
||||
$ERRORLOG = '/var/log/lighttpd/error.log';
|
||||
}
|
||||
|
||||
function pi_log($message) {
|
||||
error_log(date('Y-m-d H:i:s') . ': ' . $message . "\n", 3, $GLOBALS['ERRORLOG']);
|
||||
}
|
||||
|
||||
function log_and_die($message) {
|
||||
pi_log($message);
|
||||
die($message);
|
||||
}
|
||||
|
||||
function check_cors() {
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
$ipv4 = isset($setupVars["IPV4_ADDRESS"]) ? explode("/", $setupVars["IPV4_ADDRESS"])[0] : $_SERVER['SERVER_ADDR'];
|
||||
|
||||
// Check CORS
|
||||
$AUTHORIZED_HOSTNAMES = array(
|
||||
$ipv4,
|
||||
$_SERVER["SERVER_NAME"],
|
||||
"pi.hole",
|
||||
"localhost"
|
||||
);
|
||||
|
||||
# Allow user set virtual hostnames
|
||||
$virtual_host = getenv('VIRTUAL_HOST');
|
||||
if (! empty($virtual_host))
|
||||
array_push($AUTHORIZED_HOSTNAMES, $virtual_host);
|
||||
|
||||
// Since the Host header is easily manipulated, we can only check if it's wrong and can't use it
|
||||
// to validate that the client is authorized, only unauthorized.
|
||||
$server_host = $_SERVER['HTTP_HOST'];
|
||||
|
||||
// If HTTP_HOST contains a non-standard port (!= 80) we have to strip the port
|
||||
if(strpos($server_host, ":"))
|
||||
{
|
||||
$server_host = parse_url($_SERVER['HTTP_HOST'], PHP_URL_HOST);
|
||||
}
|
||||
|
||||
if(isset($_SERVER['HTTP_HOST']) && !in_array($server_host, $AUTHORIZED_HOSTNAMES)) {
|
||||
log_and_die("Failed Host Check: " . $server_host .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
|
||||
}
|
||||
|
||||
if(isset($_SERVER['HTTP_ORIGIN'])) {
|
||||
$server_origin = $_SERVER['HTTP_ORIGIN'];
|
||||
|
||||
// If HTTP_ORIGIN contains a non-standard port (!= 80) we have to strip the port
|
||||
if(strpos($server_origin, ":"))
|
||||
{
|
||||
$server_origin = parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
|
||||
}
|
||||
|
||||
if(!in_array($server_origin, $AUTHORIZED_HOSTNAMES)) {
|
||||
log_and_die("Failed CORS: " . $server_origin .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
|
||||
}
|
||||
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}");
|
||||
}
|
||||
// If there's no HTTP_ORIGIN, CORS should not be used
|
||||
}
|
||||
|
||||
function check_csrf($token) {
|
||||
// Check CSRF token
|
||||
$session_started = function_exists("session_status") ?
|
||||
session_status() == PHP_SESSION_ACTIVE :
|
||||
session_id() == "";
|
||||
|
||||
if(!$session_started) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Credit: http://php.net/manual/en/function.hash-equals.php#119576
|
||||
if(!function_exists('hash_equals')) {
|
||||
function hash_equals($known_string, $user_string) {
|
||||
$ret = 0;
|
||||
|
||||
if (strlen($known_string) !== strlen($user_string)) {
|
||||
$user_string = $known_string;
|
||||
$ret = 1;
|
||||
}
|
||||
|
||||
$res = $known_string ^ $user_string;
|
||||
|
||||
for ($i = strlen($res) - 1; $i >= 0; --$i) {
|
||||
$ret |= ord($res[$i]);
|
||||
}
|
||||
|
||||
return !$ret;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($_SESSION['token']) || empty($token) || !hash_equals($_SESSION['token'], $token)) {
|
||||
log_and_die("Wrong token");
|
||||
}
|
||||
}
|
||||
|
||||
function check_domain() {
|
||||
if(isset($_POST['domain'])){
|
||||
$validDomain = is_valid_domain_name($_POST['domain']);
|
||||
if(!$validDomain){
|
||||
log_and_die($_POST['domain']. ' is not a valid domain');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function list_verify($type) {
|
||||
if(!isset($_POST['domain']) || !isset($_POST['list']) || !(isset($_POST['pw']) || isset($_POST['token']))) {
|
||||
log_and_die("Missing POST variables");
|
||||
}
|
||||
|
||||
if(isset($_POST['token']))
|
||||
{
|
||||
check_cors();
|
||||
check_csrf($_POST['token']);
|
||||
}
|
||||
elseif(isset($_POST['pw']))
|
||||
{
|
||||
require("password.php");
|
||||
if(strlen($pwhash) == 0)
|
||||
{
|
||||
log_and_die("No password set - ${type}listing with password not supported");
|
||||
}
|
||||
elseif($wrongpassword)
|
||||
{
|
||||
log_and_die("Wrong password - ${type}listing of ${_POST['domain']} not permitted");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_and_die("Not allowed!");
|
||||
}
|
||||
check_domain();
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,704 @@
|
||||
<?php
|
||||
$log = array();
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
|
||||
$hosts = file_exists("/etc/hosts") ? file("/etc/hosts") : array();
|
||||
|
||||
// Check if pihole.log exists and is readable
|
||||
$logListName = checkfile("/var/log/pihole.log");
|
||||
$log = new \SplFileObject($logListName);
|
||||
|
||||
// Check if preEventHorizon exists and is readable
|
||||
$gravityListName = checkfile("/etc/pihole/list.preEventHorizon");
|
||||
$gravity = new \SplFileObject($gravityListName);
|
||||
|
||||
// whitelist.txt is optional and might not be there
|
||||
$whiteListFile = checkfile("/etc/pihole/whitelist.txt");
|
||||
$whitelist = new \SplFileObject($whiteListFile);
|
||||
|
||||
// blacklist.txt is optional and might not be there
|
||||
$blackListFile = checkfile("/etc/pihole/blacklist.txt");
|
||||
$blacklist = new \SplFileObject($blackListFile);
|
||||
|
||||
if(isset($setupVars["API_PRIVACY_MODE"]))
|
||||
{
|
||||
$privacyMode = $setupVars["API_PRIVACY_MODE"];
|
||||
}
|
||||
else
|
||||
{
|
||||
$privacyMode = false;
|
||||
}
|
||||
|
||||
/******* Public Members ********/
|
||||
function getSummaryData() {
|
||||
$domains_being_blocked = gravityCount();
|
||||
|
||||
$dns_queries_today = countDnsQueries();
|
||||
|
||||
$ads_blocked_today = countBlockedQueries();
|
||||
|
||||
$ads_percentage_today = $dns_queries_today > 0 ? ($ads_blocked_today / $dns_queries_today * 100) : 0;
|
||||
|
||||
return array(
|
||||
'domains_being_blocked' => $domains_being_blocked,
|
||||
'dns_queries_today' => $dns_queries_today,
|
||||
'ads_blocked_today' => $ads_blocked_today,
|
||||
'ads_percentage_today' => $ads_percentage_today,
|
||||
);
|
||||
}
|
||||
|
||||
function getOverTimeData() {
|
||||
global $log;
|
||||
|
||||
// Get log lines
|
||||
$dns_queries = getDnsQueries($log);
|
||||
|
||||
// Get list of ad domains
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
// Bin log entries separated into Domains and Ads in 1 hour intervals
|
||||
list($domains_over_time, $ads_over_time) = overTime($dns_queries, $gravity_domains);
|
||||
|
||||
// Align arrays
|
||||
$domains_over_time = overTime($dns_queries);
|
||||
$ads_over_time = overTime($ads_blocked);
|
||||
|
||||
// Provide a minimal valid array if there have are no blocked
|
||||
// queries at all. Otherwise the output of the API is inconsistent.
|
||||
if(count($ads_blocked) == 0)
|
||||
{
|
||||
$ads_over_time = [1 => 0];
|
||||
}
|
||||
|
||||
alignTimeArrays($ads_over_time, $domains_over_time);
|
||||
return Array(
|
||||
'domains_over_time' => $domains_over_time,
|
||||
'ads_over_time' => $ads_over_time,
|
||||
);
|
||||
}
|
||||
|
||||
function getOverTimeData10mins() {
|
||||
global $log;
|
||||
|
||||
// Get log lines
|
||||
$dns_queries = getDnsQueries($log);
|
||||
|
||||
// Get list of ad domains
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
// Bin log entries separated into Domains and Ads in 10 minute intervals
|
||||
list($domains_over_time, $ads_over_time) = overTime10mins($dns_queries, $gravity_domains);
|
||||
|
||||
// Align arrays (in case there have been hours without ad queries)
|
||||
|
||||
$domains_over_time = overTime10mins($dns_queries);
|
||||
$ads_over_time = overTime10mins($ads_blocked);
|
||||
|
||||
// Provide a minimal valid array if there have are no blocked
|
||||
// queries at all. Otherwise the output of the API is inconsistent.
|
||||
if(count($ads_blocked) == 0)
|
||||
{
|
||||
$ads_over_time = [1 => 0];
|
||||
}
|
||||
|
||||
alignTimeArrays($ads_over_time, $domains_over_time);
|
||||
return Array(
|
||||
'domains_over_time' => $domains_over_time,
|
||||
'ads_over_time' => $ads_over_time,
|
||||
);
|
||||
}
|
||||
|
||||
function getTopItems($argument) {
|
||||
global $log,$setupVars,$privacyMode;
|
||||
|
||||
// Process log file
|
||||
$dns_domains = getDnsQueryDomains($log);
|
||||
// Get list of ad domains
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
// Exclude domains the user doesn't want to see
|
||||
if(isset($setupVars["API_EXCLUDE_DOMAINS"]))
|
||||
{
|
||||
excludeFromList($dns_domains, "API_EXCLUDE_DOMAINS");
|
||||
}
|
||||
|
||||
// Sort array in descending order
|
||||
arsort($dns_domains);
|
||||
|
||||
// Prepare arrays and counters for Top Items
|
||||
$topDomains = []; $domaincounter = 0;
|
||||
$topAds = []; $adcounter = 0;
|
||||
|
||||
// Default number of Top Items to show is 10
|
||||
$qty = 10;
|
||||
|
||||
// If argument is numeric, the user may want to
|
||||
// see a different number of entries
|
||||
if(is_numeric($argument))
|
||||
{
|
||||
$qty = intval($argument);
|
||||
}
|
||||
|
||||
// Process sorted domain names
|
||||
foreach ($dns_domains as $key => $value) {
|
||||
if(isset($gravity_domains[$key]) && $adcounter < $qty)
|
||||
{
|
||||
// New entry for Top Ads
|
||||
$topAds[$key] = $value;
|
||||
$adcounter++;
|
||||
}
|
||||
else if($domaincounter < $qty && !$privacyMode)
|
||||
{
|
||||
// New entry for Top Domains
|
||||
$topDomains[$key] = $value;
|
||||
$domaincounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already collected enough entries for both lists
|
||||
// Exit loop early
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Array(
|
||||
'top_queries' => $topDomains,
|
||||
'top_ads' => $topAds,
|
||||
);
|
||||
}
|
||||
|
||||
function getRecentItems($qty) {
|
||||
global $log;
|
||||
$dns_queries = getDnsQueries($log);
|
||||
return Array(
|
||||
'recent_queries' => getRecent($dns_queries, $qty)
|
||||
);
|
||||
}
|
||||
|
||||
function getIpvType() {
|
||||
global $log;
|
||||
$dns_queries = getDnsQueries($log);
|
||||
$queryTypes = array();
|
||||
|
||||
foreach($dns_queries as $query) {
|
||||
$info = trim(explode(": ", $query)[1]);
|
||||
$queryType = explode(" ", $info)[0];
|
||||
if (isset($queryTypes[$queryType])) {
|
||||
$queryTypes[$queryType]++;
|
||||
}
|
||||
else {
|
||||
$queryTypes[$queryType] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $queryTypes;
|
||||
}
|
||||
|
||||
function resolveIPs(&$array) {
|
||||
$hostarray = [];
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
$hostname = gethostbyaddr($key);
|
||||
// If we found a hostname for the IP, replace it
|
||||
if($hostname)
|
||||
{
|
||||
// Generate HOST entry
|
||||
$hostarray["$hostname|$key"] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate IP entry
|
||||
$hostarray[$key] = $value;
|
||||
}
|
||||
}
|
||||
$array = $hostarray;
|
||||
|
||||
// Sort new array
|
||||
arsort($array);
|
||||
}
|
||||
|
||||
function getForwardDestinations() {
|
||||
global $log, $setupVars;
|
||||
$forwards = getForwards($log);
|
||||
$destinations = array();
|
||||
foreach ($forwards as $forward) {
|
||||
$exploded = explode(" ", trim($forward));
|
||||
$dest = $exploded[count($exploded) - 1];
|
||||
if (isset($destinations[$dest])) {
|
||||
$destinations[$dest]++;
|
||||
}
|
||||
else {
|
||||
$destinations[$dest] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(istrue($setupVars["API_GET_UPSTREAM_DNS_HOSTNAME"]))
|
||||
{
|
||||
resolveIPs($destinations);
|
||||
}
|
||||
|
||||
return $destinations;
|
||||
|
||||
}
|
||||
|
||||
// Check for existance of variable
|
||||
// and test it only if it exists
|
||||
function istrue(&$argument) {
|
||||
$ret = false;
|
||||
if(isset($argument))
|
||||
{
|
||||
if($argument)
|
||||
{
|
||||
$ret = true;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function getQuerySources() {
|
||||
global $log, $setupVars;
|
||||
$dns_queries = getDnsQueries($log);
|
||||
$sources = array();
|
||||
foreach($dns_queries as $query) {
|
||||
$exploded = explode(" ", $query);
|
||||
$ip = trim($exploded[count($exploded)-1]);
|
||||
if (isset($sources[$ip])) {
|
||||
$sources[$ip]++;
|
||||
}
|
||||
else {
|
||||
$sources[$ip] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
global $setupVars;
|
||||
if(isset($setupVars["API_EXCLUDE_CLIENTS"]))
|
||||
{
|
||||
excludeFromList($sources, "API_EXCLUDE_CLIENTS");
|
||||
}
|
||||
|
||||
arsort($sources);
|
||||
$sources = array_slice($sources, 0, 10);
|
||||
|
||||
if(istrue($setupVars["API_GET_CLIENT_HOSTNAME"]))
|
||||
{
|
||||
resolveIPs($sources);
|
||||
}
|
||||
|
||||
return Array(
|
||||
'top_sources' => $sources
|
||||
);
|
||||
}
|
||||
|
||||
$showBlocked = false;
|
||||
$showPermitted = false;
|
||||
|
||||
function setShowBlockedPermitted()
|
||||
{
|
||||
global $showBlocked, $showPermitted, $setupVars;
|
||||
if(isset($setupVars["API_QUERY_LOG_SHOW"]))
|
||||
{
|
||||
if($setupVars["API_QUERY_LOG_SHOW"] === "all")
|
||||
{
|
||||
$showBlocked = true;
|
||||
$showPermitted = true;
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "permittedonly")
|
||||
{
|
||||
$showBlocked = false;
|
||||
$showPermitted = true;
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "blockedonly")
|
||||
{
|
||||
$showBlocked = true;
|
||||
$showPermitted = false;
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "nothing")
|
||||
{
|
||||
$showBlocked = false;
|
||||
$showPermitted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid settings, show everything
|
||||
$showBlocked = true;
|
||||
$showPermitted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$showBlocked = true;
|
||||
$showPermitted = true;
|
||||
}
|
||||
}
|
||||
|
||||
function getAllQueries($orderBy) {
|
||||
global $log,$showBlocked,$showPermitted,$privacyMode;
|
||||
$allQueries = array("data" => array());
|
||||
$dns_queries = getDnsQueries($log);
|
||||
|
||||
// Create empty array for gravity
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
setShowBlockedPermitted();
|
||||
|
||||
// Privacy mode?
|
||||
if($privacyMode)
|
||||
{
|
||||
$showPermitted = false;
|
||||
}
|
||||
|
||||
if(!$showBlocked && !$showPermitted)
|
||||
{
|
||||
// Nothing to do for us here
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($dns_queries as $query) {
|
||||
$time = date_create(substr($query, 0, 16));
|
||||
$exploded = explode(" ", trim($query));
|
||||
$domain = $exploded[count($exploded)-3];
|
||||
$tmp = $exploded[count($exploded)-4];
|
||||
|
||||
$status = isset($gravity_domains[$domain]) ? "Pi-holed" : "OK";
|
||||
if(($status === "Pi-holed" && $showBlocked) || ($status === "OK" && $showPermitted))
|
||||
{
|
||||
$type = substr($exploded[count($exploded)-4], 6, -1);
|
||||
$client = $exploded[count($exploded)-1];
|
||||
|
||||
if($orderBy == "orderByClientDomainTime"){
|
||||
$allQueries['data'][hasHostName($client)][$domain][$time->format('Y-m-d\TH:i:s')] = $status;
|
||||
}elseif ($orderBy == "orderByClientTimeDomain"){
|
||||
$allQueries['data'][hasHostName($client)][$time->format('Y-m-d\TH:i:s')][$domain] = $status;
|
||||
}elseif ($orderBy == "orderByTimeClientDomain"){
|
||||
$allQueries['data'][$time->format('Y-m-d\TH:i:s')][hasHostName($client)][$domain] = $status;
|
||||
}elseif ($orderBy == "orderByTimeDomainClient"){
|
||||
$allQueries['data'][$time->format('Y-m-d\TH:i:s')][$domain][hasHostName($client)] = $status;
|
||||
}elseif ($orderBy == "orderByDomainClientTime"){
|
||||
$allQueries['data'][$domain][hasHostName($client)][$time->format('Y-m-d\TH:i:s')] = $status;
|
||||
}elseif ($orderBy == "orderByDomainTimeClient"){
|
||||
$allQueries['data'][$domain][$time->format('Y-m-d\TH:i:s')][hasHostName($client)] = $status;
|
||||
}else{
|
||||
array_push($allQueries['data'], array(
|
||||
$time->format('Y-m-d\TH:i:s'),
|
||||
$type,
|
||||
$domain,
|
||||
hasHostName($client),
|
||||
$status,
|
||||
""
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $allQueries;
|
||||
}
|
||||
|
||||
function tailPiholeLog($param) {
|
||||
// Not using SplFileObject here, since direct
|
||||
// usage of f-streams will be much faster for
|
||||
// files as large as the pihole.log
|
||||
global $logListName;
|
||||
$file = fopen($logListName,"r");
|
||||
$offset = intval($param);
|
||||
if($offset > 0)
|
||||
{
|
||||
// Seeks on the file pointer where we want to continue reading is known
|
||||
fseek($file, $offset);
|
||||
$lines = [];
|
||||
while (!feof($file)) {
|
||||
array_push($lines,fgets($file));
|
||||
}
|
||||
return ["offset" => ftell($file), "lines" => $lines];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Locate the current position of the file read/write pointer
|
||||
fseek($file, -1, SEEK_END);
|
||||
// Add one to skip the very last "\n" in the log file
|
||||
return ["offset" => ftell($file)+1];
|
||||
}
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
/******** Private Members ********/
|
||||
function gravityCount() {
|
||||
global $gravityListName,$blackListFile;
|
||||
$preEventHorizon = exec("grep -c ^ $gravityListName");
|
||||
$blacklist = exec("grep -c ^ $blackListFile");
|
||||
return ($preEventHorizon + $blacklist);
|
||||
}
|
||||
|
||||
function getDnsQueries(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": query[A") !== false) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function getDnsQueryDomains(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$domains = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": query[A") !== false) {
|
||||
$exploded = explode(" ", $line);
|
||||
$domain = trim($exploded[count($exploded) - 3]);
|
||||
if (isset($domains[$domain])) {
|
||||
$domains[$domain]++;
|
||||
}
|
||||
else {
|
||||
$domains[$domain] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $domains;
|
||||
}
|
||||
|
||||
function countDnsQueries() {
|
||||
global $logListName;
|
||||
return exec("grep -c \": query\\[A\" $logListName");
|
||||
}
|
||||
|
||||
function getDnsQueriesAll(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": query[A") || strpos($line, "gravity.list") || strpos($line, ": forwarded") !== false) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function getDomains($file, &$array, $action){
|
||||
$file->rewind();
|
||||
foreach ($file as $line) {
|
||||
// Strip newline (and possibly carriage return) from end of key
|
||||
$key = rtrim($line);
|
||||
// if $action = true -> we want that domain to be ADDED to the list
|
||||
// doesn't harm to do this if it has already been set before
|
||||
// (e.g. once in gravity list, once in blacklist)
|
||||
if($action && strlen($key) > 0)
|
||||
{
|
||||
// $action is true (we want to add) *and* key is not empty
|
||||
$array[$key] = true;
|
||||
}
|
||||
elseif(!$action && isset($array[$key]))
|
||||
{
|
||||
// $action is false (we want to remove) *and* key is set
|
||||
unset($array[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getGravity() {
|
||||
global $gravity,$whitelist,$blacklist;
|
||||
$domains = [];
|
||||
|
||||
// ADD (true) preEventHorizon domains
|
||||
getDomains($gravity, $domains, true);
|
||||
|
||||
// ADD (true) blacklist domains
|
||||
getDomains($blacklist, $domains, true);
|
||||
|
||||
// REMOVE (false) whitelist domains
|
||||
getDomains($whitelist, $domains, false);
|
||||
|
||||
return $domains;
|
||||
}
|
||||
|
||||
function getBlockedQueries(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
$exploded = explode(" ", $line);
|
||||
if(count($exploded) == 8 || count($exploded) == 10) {
|
||||
// Structure of data is currently like:
|
||||
// Array
|
||||
// (
|
||||
// [0] => Dec
|
||||
// [1] => 19
|
||||
// [2] => 11:21:51
|
||||
// [3] => dnsmasq[2584]:
|
||||
// [4] => /etc/pihole/gravity.list
|
||||
// [5] => doubleclick.com
|
||||
// [6] => is
|
||||
// [7] => ip.of.pi.hole
|
||||
// )
|
||||
// with extra logging enabled
|
||||
// Array
|
||||
// (
|
||||
// [0] => Dec
|
||||
// [1] => 19
|
||||
// [2] => 11:21:51
|
||||
// [3] => dnsmasq[2584]:
|
||||
// [4] => 1 (identifier)
|
||||
// [5] => 1.2.3.4/12345
|
||||
// [6] => /etc/pihole/gravity.list
|
||||
// [7] => doubleclick.com
|
||||
// [8] => is
|
||||
// [9] => ip.of.pi.hole
|
||||
// )
|
||||
$list = $exploded[count($exploded)-4];
|
||||
$is = $exploded[count($exploded)-2];
|
||||
// Consider only gravity.list as DNS source (not e.g. hostname.list)
|
||||
if(substr($list, strlen($list) - 12, 12) === "gravity.list" && $is === "is") {
|
||||
$lines[] = $line;
|
||||
};
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function countBlockedQueries() {
|
||||
global $logListName;
|
||||
return exec("grep \"gravity.list\" $logListName | grep -c \" is \"");
|
||||
}
|
||||
|
||||
function getForwards(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": forwarded") !== false) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function excludeFromList(&$array,$key)
|
||||
{
|
||||
global $setupVars;
|
||||
$domains = explode(",",$setupVars[$key]);
|
||||
foreach ($domains as $domain) {
|
||||
if(isset($array[$domain]))
|
||||
{
|
||||
unset($array[$domain]);
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
function overTime($entries, $gravity_domains) {
|
||||
$byTimeDomains = [];
|
||||
$byTimeAds = [];
|
||||
foreach ($entries as $entry) {
|
||||
$time = date_create(substr($entry, 0, 16));
|
||||
$hour = $time->format('G');
|
||||
|
||||
$exploded = explode(" ", $entry);
|
||||
$domain = trim($exploded[count($exploded) - 3]);
|
||||
|
||||
if(isset($gravity_domains[$domain]))
|
||||
{
|
||||
if (isset($byTimeAds[$time])) {
|
||||
$byTimeAds[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeAds[$time] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($byTimeDomains[$time])) {
|
||||
$byTimeDomains[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeDomains[$time] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [$byTimeDomains,$byTimeAds];
|
||||
}
|
||||
|
||||
function overTime10mins($entries, $gravity_domains) {
|
||||
$byTimeDomains = [];
|
||||
$byTimeAds = [];
|
||||
foreach ($entries as $entry) {
|
||||
$time = date_create(substr($entry, 0, 16));
|
||||
$hour = $time->format('G');
|
||||
$minute = $time->format('i');
|
||||
|
||||
// 00:00 - 00:09 -> 0
|
||||
// 00:10 - 00:19 -> 1
|
||||
// ...
|
||||
// 12:00 - 12:10 -> 72
|
||||
// ...
|
||||
// 15:30 - 15:39 -> 93
|
||||
// etc.
|
||||
$time = ($minute-$minute%10)/10 + 6*$hour;
|
||||
|
||||
$exploded = explode(" ", $entry);
|
||||
$domain = trim($exploded[count($exploded) - 3]);
|
||||
|
||||
if(isset($gravity_domains[$domain]))
|
||||
{
|
||||
if (isset($byTimeAds[$time])) {
|
||||
$byTimeAds[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeAds[$time] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($byTimeDomains[$time])) {
|
||||
$byTimeDomains[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeDomains[$time] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [$byTimeDomains,$byTimeAds];
|
||||
}
|
||||
|
||||
function alignTimeArrays(&$times1, &$times2) {
|
||||
if(count($times1) == 0 || count($times2) < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$max = max(array_merge(array_keys($times1), array_keys($times2)));
|
||||
$min = min(array_merge(array_keys($times1), array_keys($times2)));
|
||||
|
||||
for ($i = $min; $i <= $max; $i++) {
|
||||
if (!isset($times2[$i])) {
|
||||
$times2[$i] = 0;
|
||||
}
|
||||
if (!isset($times1[$i])) {
|
||||
$times1[$i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ksort($times1);
|
||||
ksort($times2);
|
||||
}
|
||||
|
||||
function getRecent($queries, $qty){
|
||||
$recent = array();
|
||||
foreach (array_slice($queries, -$qty) as $query) {
|
||||
$queryArray = array();
|
||||
$exploded = explode(" ", $query);
|
||||
$time = date_create(substr($query, 0, 16));
|
||||
$queryArray['time'] = $time->format('h:i:s a');
|
||||
$queryArray['domain'] = trim($exploded[count($exploded) - 3]);
|
||||
$queryArray['ip'] = trim($exploded[count($exploded)-1]);
|
||||
array_push($recent, $queryArray);
|
||||
|
||||
}
|
||||
return array_reverse($recent);
|
||||
}
|
||||
|
||||
function hasHostName($var){
|
||||
global $hosts;
|
||||
foreach ($hosts as $host){
|
||||
$x = preg_split('/\s+/', $host);
|
||||
if ( $var == $x[0] ){
|
||||
$var = $x[1] . "($var)";
|
||||
}
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,48 @@
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
<footer class="main-footer">
|
||||
<?php
|
||||
// Check if on a dev branch
|
||||
$piholeBranch = exec("cd /etc/.pihole/ && git rev-parse --abbrev-ref HEAD");
|
||||
$webBranch = exec("git rev-parse --abbrev-ref HEAD");
|
||||
|
||||
// Use vDev if not on master
|
||||
if($piholeBranch !== "master") {
|
||||
$piholeVersion = "vDev";
|
||||
$piholeCommit = exec("cd /etc/.pihole/ && git describe --long --dirty --tags");
|
||||
}
|
||||
else {
|
||||
$piholeVersion = exec("cd /etc/.pihole/ && git describe --tags --abbrev=0");
|
||||
}
|
||||
|
||||
if($webBranch !== "master") {
|
||||
$webVersion = "vDev";
|
||||
$webCommit = exec("git describe --long --dirty --tags");
|
||||
}
|
||||
else {
|
||||
$webVersion = exec("git describe --tags --abbrev=0");
|
||||
}
|
||||
?>
|
||||
<div class="pull-right hidden-xs <?php if(isset($piholeCommit) || isset($webCommit)) { ?>hidden-md<?php } ?>">
|
||||
<b>Pi-hole Version </b> <span id="piholeVersion"><?php echo $piholeVersion; ?></span><?php if(isset($piholeCommit)) { echo " (".$piholeBranch.", ".$piholeCommit.")"; } ?>
|
||||
<b>Web Interface Version </b> <span id="webVersion"><?php echo $webVersion; ?></span><?php if(isset($webCommit)) { echo " (".$webBranch.", ".$webCommit.")"; } ?>
|
||||
</div>
|
||||
<div><i class="fa fa-github"></i> <strong><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate</a></strong> if you found this useful.</div>
|
||||
</footer>
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
<script src="scripts/vendor/jquery.min.js"></script>
|
||||
<script src="scripts/vendor/jquery-ui.min.js"></script>
|
||||
<script src="style/vendor/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="scripts/vendor/app.min.js"></script>
|
||||
|
||||
<script src="scripts/vendor/jquery.dataTables.min.js"></script>
|
||||
<script src="scripts/vendor/dataTables.bootstrap.min.js"></script>
|
||||
<script src="scripts/vendor/Chart.bundle.min.js"></script>
|
||||
|
||||
<script src="scripts/pi-hole/js/footer.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
function is_valid_domain_name($domain_name)
|
||||
{
|
||||
return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) && //valid chars check
|
||||
preg_match("/^.{1,253}$/", $domain_name) && //overall length check
|
||||
preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); //length of each label
|
||||
}
|
||||
|
||||
function checkfile($filename) {
|
||||
if(is_readable($filename))
|
||||
{
|
||||
return $filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
// substitute dummy file
|
||||
return "/dev/null";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
if(!isset($_GET['list']))
|
||||
die();
|
||||
|
||||
$type = $_GET['list'];
|
||||
|
||||
if($type !== "white" && $type !== "black")
|
||||
die("Invalid list parameter");
|
||||
|
||||
require "func.php";
|
||||
|
||||
$rawList = file_get_contents(checkfile("/etc/pihole/${type}list.txt"));
|
||||
$list = explode("\n", $rawList);
|
||||
|
||||
// Get rid of empty lines
|
||||
for($i = sizeof($list)-1; $i >= 0; $i--) {
|
||||
if($list[$i] == "")
|
||||
unset($list[$i]);
|
||||
}
|
||||
|
||||
function filterArray(&$inArray) {
|
||||
$outArray = array();
|
||||
foreach ($inArray as $key=>$value) {
|
||||
if (is_array($value)) {
|
||||
$outArray[htmlspecialchars($key)] = filterArray($value);
|
||||
} else {
|
||||
$outArray[htmlspecialchars($key)] = htmlspecialchars($value);
|
||||
}
|
||||
}
|
||||
return $outArray;
|
||||
}
|
||||
|
||||
// Protect against XSS attacks
|
||||
$list = filterArray($list);
|
||||
echo json_encode(array_values($list));
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
require "password.php";
|
||||
if(!$auth) die("Not authorized");
|
||||
|
||||
ob_end_flush();
|
||||
ini_set("output_buffering", "0");
|
||||
ob_implicit_flush(true);
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
|
||||
function echoEvent($datatext) {
|
||||
echo "data: ".implode("\ndata: ", explode("\n", $datatext))."\n\n";
|
||||
}
|
||||
|
||||
// echoEvent("***START***");
|
||||
|
||||
$proc = popen("sudo pihole -g", 'r');
|
||||
while (!feof($proc)) {
|
||||
echoEvent(fread($proc, 4096));
|
||||
}
|
||||
|
||||
// echoEvent("***END***");
|
||||
?>
|
||||
@@ -0,0 +1,496 @@
|
||||
<?php
|
||||
require "scripts/pi-hole/php/auth.php";
|
||||
require "scripts/pi-hole/php/password.php";
|
||||
|
||||
check_cors();
|
||||
|
||||
// Try to get temperature value from different places (OS dependent)
|
||||
if(file_exists("/sys/class/thermal/thermal_zone0/temp"))
|
||||
{
|
||||
$output = rtrim(file_get_contents("/sys/class/thermal/thermal_zone0/temp"));
|
||||
}
|
||||
elseif (file_exists("/sys/class/hwmon/hwmon0/temp1_input"))
|
||||
{
|
||||
$output = rtrim(file_get_contents("/sys/class/hwmon/hwmon0/temp1_input"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$output = "";
|
||||
}
|
||||
|
||||
// Test if we succeeded in getting the temperature
|
||||
if(is_numeric($output))
|
||||
{
|
||||
// $output could be either 4-5 digits or 2-3, and we only divide by 1000 if it's 4-5
|
||||
// ex. 39007 vs 39
|
||||
$celsius = intVal($output);
|
||||
|
||||
// If celsius is greater than 1 degree and is in the 4-5 digit format
|
||||
if($celsius > 1000) {
|
||||
// Use multiplication to get around the division-by-zero error
|
||||
$celsius *= 1e-3;
|
||||
}
|
||||
|
||||
$kelvin = $celsius + 273.15;
|
||||
$fahrenheit = ($celsius*9./5)+32.0;
|
||||
|
||||
if(isset($setupVars['TEMPERATUREUNIT']))
|
||||
{
|
||||
$temperatureunit = $setupVars['TEMPERATUREUNIT'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$temperatureunit = "C";
|
||||
}
|
||||
// Override temperature unit setting if it is changed via Settings page
|
||||
if(isset($_POST["tempunit"]))
|
||||
{
|
||||
$temperatureunit = $_POST["tempunit"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing can be colder than -273.15 degree Celsius (= 0 Kelvin)
|
||||
// This is the minimum temperature possible (AKA absolute zero)
|
||||
$celsius = -273.16;
|
||||
}
|
||||
|
||||
// Get load
|
||||
$loaddata = sys_getloadavg();
|
||||
// Get number of processing units available to PHP
|
||||
// (may be less than the number of online processors)
|
||||
$nproc = shell_exec('nproc');
|
||||
|
||||
// Get memory usage
|
||||
$data = explode("\n", file_get_contents("/proc/meminfo"));
|
||||
$meminfo = array();
|
||||
if(count($data) > 0)
|
||||
{
|
||||
foreach ($data as $line) {
|
||||
$expl = explode(":", trim($line));
|
||||
if(count($expl) == 2)
|
||||
{
|
||||
// remove " kB" from the end of the string and make it an integer
|
||||
$meminfo[$expl[0]] = intVal(substr($expl[1],0, -3));
|
||||
}
|
||||
}
|
||||
$memory_used = $meminfo["MemTotal"]-$meminfo["MemFree"]-$meminfo["Buffers"]-$meminfo["Cached"];
|
||||
$memory_total = $meminfo["MemTotal"];
|
||||
$memory_usage = $memory_used/$memory_total;
|
||||
}
|
||||
else
|
||||
{
|
||||
$memory_usage = -1;
|
||||
}
|
||||
|
||||
|
||||
// For session timer
|
||||
$maxlifetime = ini_get("session.gc_maxlifetime");
|
||||
|
||||
// Generate CSRF token
|
||||
if(empty($_SESSION['token'])) {
|
||||
$_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32));
|
||||
}
|
||||
$token = $_SESSION['token'];
|
||||
|
||||
if(isset($setupVars['WEBUIBOXEDLAYOUT']))
|
||||
{
|
||||
if($setupVars['WEBUIBOXEDLAYOUT'] === "boxed")
|
||||
{
|
||||
$boxedlayout = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$boxedlayout = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$boxedlayout = true;
|
||||
}
|
||||
|
||||
// Override layout setting if layout is changed via Settings page
|
||||
if(isset($_POST["field"]))
|
||||
{
|
||||
if($_POST["field"] === "webUI" && isset($_POST["boxedlayout"]))
|
||||
{
|
||||
$boxedlayout = true;
|
||||
}
|
||||
elseif($_POST["field"] === "webUI" && !isset($_POST["boxedlayout"]))
|
||||
{
|
||||
$boxedlayout = false;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://api.github.com; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'">
|
||||
<title>Pi-hole Admin Console</title>
|
||||
<!-- Usually browsers proactively perform domain name resolution on links that the user may choose to follow. We disable DNS prefetching here -->
|
||||
<meta http-equiv="x-dns-prefetch-control" content="off">
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
|
||||
<meta name="theme-color" content="#367fa9">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="img/logo.svg">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="img/logo.svg">
|
||||
<meta name="msapplication-TileColor" content="#367fa9">
|
||||
<meta name="msapplication-TileImage" content="img/logo.svg">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<link href="style/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style/vendor/font-awesome-4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style/vendor/ionicons-2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style/vendor/dataTables.bootstrap.min.css" rel="stylesheet" type="text/css" />
|
||||
|
||||
<link href="style/vendor/AdminLTE.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style/vendor/skin-blue.min.css" rel="stylesheet" type="text/css" />
|
||||
<link rel="icon" type="image/png" sizes="160x160" href="img/logo.svg" />
|
||||
<style type="text/css">
|
||||
.glow { text-shadow: 0px 0px 5px #fff; }
|
||||
h3 { transition-duration: 500ms }
|
||||
</style>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="scripts/vendor/html5shiv.min.js"></script>
|
||||
<script src="scripts/vendor/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body class="skin-blue sidebar-mini <?php if($boxedlayout){ ?>layout-boxed<?php } ?>">
|
||||
<!-- JS Warning -->
|
||||
<div>
|
||||
<link rel="stylesheet" type="text/css" href="style/vendor/js-warn.css">
|
||||
<input type="checkbox" id="js-hide" />
|
||||
<div class="js-warn" id="js-warn-exit"><h1>Javascript Is Disabled</h1><p>Javascript seems to be disabled. This will break some site features.</p>
|
||||
<p>To enable Javascript click <a href="http://www.enable-javascript.com/" target="_blank">here</a></p><label for="js-hide">Close</label></div>
|
||||
</div>
|
||||
<!-- /JS Warning -->
|
||||
<script src="scripts/pi-hole/js/header.js"></script>
|
||||
<!-- Send token to JS -->
|
||||
<div id="token" hidden><?php echo $token ?></div>
|
||||
<div class="wrapper">
|
||||
<header class="main-header">
|
||||
<!-- Logo -->
|
||||
<a href="http://pi-hole.net" class="logo">
|
||||
<!-- mini logo for sidebar mini 50x50 pixels -->
|
||||
<span class="logo-mini"><b>P</b>H</span>
|
||||
<!-- logo for regular state and mobile devices -->
|
||||
<span class="logo-lg"><b>Pi</b>-hole</span>
|
||||
</a>
|
||||
<!-- Header Navbar: style can be found in header.less -->
|
||||
<nav class="navbar navbar-static-top" role="navigation">
|
||||
<!-- Sidebar toggle button-->
|
||||
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
<!-- User Account: style can be found in dropdown.less -->
|
||||
<li id="dropdown-menu" class="dropdown user user-menu">
|
||||
<a href="#" class="dropdown-toggle">
|
||||
<img src="img/logo.svg" class="user-image" style="border-radius: initial" sizes="160x160" alt="Pi-hole logo" />
|
||||
<span class="hidden-xs">Pi-hole</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<!-- User image -->
|
||||
<li class="user-header">
|
||||
<img src="img/logo.svg" sizes="160x160" alt="User Image" />
|
||||
<p>
|
||||
Open Source Ad Blocker
|
||||
<small>Designed For Raspberry Pi</small>
|
||||
</p>
|
||||
</li>
|
||||
<!-- Menu Body -->
|
||||
<li class="user-body">
|
||||
<div class="col-xs-4 text-center">
|
||||
<a href="https://github.com/pi-hole/pi-hole">GitHub</a>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center">
|
||||
<a href="http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0/">Details</a>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center">
|
||||
<a href="https://github.com/pi-hole/pi-hole/releases">Updates</a>
|
||||
</div>
|
||||
<div class="col-xs-12 text-center" id="sessiontimer">Session is valid for <span id="sessiontimercounter"><?php if($auth && strlen($pwhash) > 0){echo $maxlifetime;}else{echo "0";} ?></span></div>
|
||||
</li>
|
||||
<!-- Menu Footer -->
|
||||
<li class="user-footer">
|
||||
<!-- Update alerts -->
|
||||
<div id="alPiholeUpdate" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
|
||||
<a class="alert-link" href="https://github.com/pi-hole/pi-hole/releases">There's an update available for this Pi-hole!</a>
|
||||
</div>
|
||||
<div id="alWebUpdate" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
|
||||
<a class="alert-link" href="https://github.com/pi-hole/AdminLTE/releases">There's an update available for this Web Interface!</a>
|
||||
</div>
|
||||
|
||||
<!-- PayPal -->
|
||||
<div>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="3J2L3Z4DHW9UY">
|
||||
<input style="display: block; margin: 0 auto;" type="image" src="img/donate.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- Left side column. contains the logo and sidebar -->
|
||||
<aside class="main-sidebar">
|
||||
<!-- sidebar: style can be found in sidebar.less -->
|
||||
<section class="sidebar">
|
||||
<!-- Sidebar user panel -->
|
||||
<div class="user-panel">
|
||||
<div class="pull-left image">
|
||||
<img src="img/logo.svg" class="img-responsive" alt="Pi-hole logo" />
|
||||
</div>
|
||||
<div class="pull-left info">
|
||||
<p>Status</p>
|
||||
<?php
|
||||
$pistatus = exec('sudo pihole status web');
|
||||
if ($pistatus == "1") {
|
||||
echo '<a href="#" id="status"><i class="fa fa-circle" style="color:#7FFF00"></i> Active</a>';
|
||||
} elseif ($pistatus == "0") {
|
||||
echo '<a href="#" id="status"><i class="fa fa-circle" style="color:#FF0000"></i> Offline</a>';
|
||||
} else {
|
||||
echo '<a href="#" id="status"><i class="fa fa-circle" style="color:#ff9900"></i> Starting</a>';
|
||||
}
|
||||
|
||||
// CPU Temp
|
||||
if ($celsius >= -273.15) {
|
||||
echo "<a href=\"#\" id=\"temperature\"><i class=\"fa fa-fire\" style=\"color:";
|
||||
if ($celsius > 60) {
|
||||
echo "#FF0000";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "#3366FF";
|
||||
}
|
||||
echo "\"></i> Temp: ";
|
||||
if($temperatureunit === "F")
|
||||
{
|
||||
echo round($fahrenheit,1) . "°F";
|
||||
}
|
||||
elseif($temperatureunit === "K")
|
||||
{
|
||||
echo round($kelvin,1) . "K";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo round($celsius,1) . "°C";
|
||||
}
|
||||
echo "</a>";
|
||||
}
|
||||
?>
|
||||
<br/>
|
||||
<?php
|
||||
echo '<a href="#"><i class="fa fa-circle" style="color:';
|
||||
if ($loaddata[0] > $nproc) {
|
||||
echo '#FF0000';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '#7FFF00';
|
||||
}
|
||||
echo '""></i> Load: ' . $loaddata[0] . ' ' . $loaddata[1] . ' '. $loaddata[2] . '</a>';
|
||||
?>
|
||||
<br/>
|
||||
<?php
|
||||
echo '<a href="#"><i class="fa fa-circle" style="color:';
|
||||
if ($memory_usage > 0.75 || $memory_usage < 0.0) {
|
||||
echo '#FF0000';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '#7FFF00';
|
||||
}
|
||||
if($memory_usage > 0.0)
|
||||
{
|
||||
echo '""></i> Memory usage: ' . sprintf("%.1f",100.0*$memory_usage) . '%</a>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '""></i> Memory usage: N/A</a>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- sidebar menu: : style can be found in sidebar.less -->
|
||||
<?php
|
||||
$scriptname = basename($_SERVER['SCRIPT_FILENAME']);
|
||||
if($scriptname === "list.php")
|
||||
{
|
||||
if($_GET["l"] === "white")
|
||||
{
|
||||
$scriptname = "whitelist";
|
||||
}
|
||||
elseif($_GET["l"] === "black")
|
||||
{
|
||||
$scriptname = "blacklist";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<ul class="sidebar-menu">
|
||||
<li class="header">MAIN NAVIGATION</li>
|
||||
<!-- Home Page -->
|
||||
<li<?php if($scriptname === "index.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="index.php">
|
||||
<i class="fa fa-home"></i> <span>Main Page</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php if($auth){ ?>
|
||||
<!-- Query Log -->
|
||||
<li<?php if($scriptname === "queries.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="queries.php">
|
||||
<i class="fa fa-file-text-o"></i> <span>Query Log</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Whitelist -->
|
||||
<li<?php if($scriptname === "whitelist"){ ?> class="active"<?php } ?>>
|
||||
<a href="list.php?l=white">
|
||||
<i class="fa fa-pencil-square-o"></i> <span>Whitelist</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Blacklist -->
|
||||
<li<?php if($scriptname === "blacklist"){ ?> class="active"<?php } ?>>
|
||||
<a href="list.php?l=black">
|
||||
<i class="fa fa-ban"></i> <span>Blacklist</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Toggle -->
|
||||
|
||||
<li id="pihole-disable" class="treeview"<?php if ($pistatus == "0") { ?> hidden="true"<?php } ?>>
|
||||
<a href="#">
|
||||
<i class="fa fa-stop"></i> <span>Disable</span> <span id="flip-status-disable"></span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-down pull-right" style="padding-right: 5px;"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li>
|
||||
<a href="#" id="pihole-disable-permanently">
|
||||
<i class="fa fa-stop"></i> <span>Permanently</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" id="pihole-disable-10s">
|
||||
<i class="fa fa-clock-o"></i> <span>For 10 seconds</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" id="pihole-disable-30s">
|
||||
<i class="fa fa-clock-o"></i> <span>For 30 seconds</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" id="pihole-disable-5m">
|
||||
<i class="fa fa-clock-o"></i> <span>For 5 minutes</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- <a href="#" id="flip-status"><i class="fa fa-stop"></i> <span>Disable</span></a> -->
|
||||
</li>
|
||||
<li id="pihole-enable" class="treeview"<?php if ($pistatus == "1") { ?> hidden="true"<?php } ?>>
|
||||
<a href="#"><i class="fa fa-play"></i> <span>Enable</span> <span id="flip-status-enable"></span></a>
|
||||
</li>
|
||||
<!-- Tools -->
|
||||
<li class="treeview <?php if($scriptname === "gravity.php" || $scriptname === "queryads.php"){ ?>active<?php } ?>">
|
||||
<a href="#">
|
||||
<i class="fa fa-folder"></i> <span>Tools</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-down pull-right" style="padding-right: 5px;"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<!-- Run gravity.sh -->
|
||||
<li<?php if($scriptname === "gravity.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="gravity.php">
|
||||
<i class="fa fa-arrow-circle-down"></i> <span>Update Lists</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Query adlists -->
|
||||
<li<?php if($scriptname === "queryads.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="queryads.php">
|
||||
<i class="fa fa-search"></i> <span>Query adlists</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail pihole.log -->
|
||||
<li<?php if($scriptname === "taillog.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="taillog.php">
|
||||
<i class="fa fa-list-ul"></i> <span>Tail pihole.log</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Settings -->
|
||||
<li<?php if($scriptname === "settings.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="settings.php">
|
||||
<i class="fa fa-gears"></i> <span>Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Logout -->
|
||||
<?php
|
||||
// Show Logout button if $auth is set and authorization is required
|
||||
if(strlen($pwhash) > 0) { ?>
|
||||
<li>
|
||||
<a href="index.php?logout">
|
||||
<i class="fa fa-user-times"></i> <span>Logout</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<!-- Login -->
|
||||
<?php
|
||||
// Show Login button if $auth is *not* set and authorization is required
|
||||
if(strlen($pwhash) > 0 && !$auth) { ?>
|
||||
<li>
|
||||
<a href="index.php?login">
|
||||
<i class="fa fa-user"></i> <span>Login</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<!-- Donate -->
|
||||
<li>
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">
|
||||
<i class="fa fa-paypal"></i> <span>Donate</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php if($auth){ ?>
|
||||
<!-- Help -->
|
||||
<li<?php if($scriptname === "help.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="help.php">
|
||||
<i class="fa fa-question-circle"></i> <span>Help</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</section>
|
||||
<!-- /.sidebar -->
|
||||
</aside>
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<?php
|
||||
// If password is not equal to the password set
|
||||
// in the setupVars.conf file, then we skip any
|
||||
// content and just complete the page. If no
|
||||
// password is set at all, we keep the current
|
||||
// behavior: everything is always authorized
|
||||
// and will be displayed
|
||||
//
|
||||
// If auth is required and not set, i.e. no successfully logged in,
|
||||
// we show the reduced version of the summary (index) page
|
||||
if(!$auth && (!isset($indexpage) || isset($_GET['login']))){
|
||||
require "scripts/pi-hole/php/loginpage.php";
|
||||
require "footer.php";
|
||||
exit();
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,54 @@
|
||||
<div class="mainbox col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div style="text-align: center;"><img src="img/logo.svg" width="<?php if ($boxedlayout) { ?>50%<?php } else { ?>30%<?php } ?>"></div><br>
|
||||
|
||||
<div class="panel-title text-center"><span class="logo-lg" style="font-size: 25px;"><b>Pi</b>-hole</span></div>
|
||||
<p class="login-box-msg">Sign in to start your session</p>
|
||||
<?php if ($wrongpassword) { ?>
|
||||
<div class="form-group has-error login-box-msg">
|
||||
<label class="control-label"><i class="fa fa-times-circle-o"></i> Wrong password!</label>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<form action="" method="post">
|
||||
<div class="form-group has-feedback <?php if ($wrongpassword) { ?>has-error<?php } ?> ">
|
||||
<input type="password" name="pw" class="form-control" placeholder="Password" autofocus>
|
||||
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-4 col-xs-offset-8">
|
||||
<button type="submit" href="#" class="btn btn-primary pull-right"><i class="glyphicon glyphicon-log-in"></i> Log in</button>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box box-<?php if (!$wrongpassword) { ?>info<?php } else { ?>danger<?php }
|
||||
if (!$wrongpassword) { ?> collapsed-box<?php } ?> box-solid">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Forgot password</h3>
|
||||
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i
|
||||
class="fa <?php if ($wrongpassword) { ?>fa-minus<?php } else { ?>fa-plus<?php } ?>"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
After installing Pi-Hole for the first time, a password is generated and displayed to the user. The
|
||||
password cannot be retrived later on, but it is possible to set a new password (or explicitly disable
|
||||
the
|
||||
password by setting an empty password) using the command
|
||||
<pre>sudo pihole -a -p newpassword</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
// Start a new PHP session (or continue an existing one)
|
||||
session_start();
|
||||
|
||||
// Read setupVars.conf file
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
// Try to read password hash from setupVars.conf
|
||||
if(isset($setupVars['WEBPASSWORD']))
|
||||
{
|
||||
$pwhash = $setupVars['WEBPASSWORD'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$pwhash = "";
|
||||
}
|
||||
|
||||
// If the user wants to log out, we free all session variables currently registered
|
||||
if(isset($_GET["logout"]))
|
||||
{
|
||||
session_unset();
|
||||
}
|
||||
|
||||
$wrongpassword = false;
|
||||
|
||||
// Test if password is set
|
||||
if(strlen($pwhash) > 0)
|
||||
{
|
||||
// Compare doubly hashes password input with saved hash
|
||||
if(isset($_POST["pw"]))
|
||||
{
|
||||
$postinput = hash('sha256',hash('sha256',$_POST["pw"]));
|
||||
if($postinput == $pwhash)
|
||||
{
|
||||
$_SESSION["hash"] = $pwhash;
|
||||
$auth = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$wrongpassword = true;
|
||||
}
|
||||
}
|
||||
// Compare auth hash with saved hash
|
||||
else if (isset($_SESSION["hash"]))
|
||||
{
|
||||
if($_SESSION["hash"] == $pwhash)
|
||||
$auth = true;
|
||||
}
|
||||
// API can use the hash to get data without logging in via plain-text password
|
||||
else if (isset($api) && isset($_GET["auth"]))
|
||||
{
|
||||
if($_GET["auth"] == $pwhash)
|
||||
$auth = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Password or hash wrong
|
||||
$auth = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No password set
|
||||
$auth = true;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
ob_end_flush();
|
||||
ini_set("output_buffering", "0");
|
||||
ob_implicit_flush(true);
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
|
||||
function echoEvent($datatext) {
|
||||
echo "data: ".implode("\ndata: ", explode("\n", $datatext))."\n\n";
|
||||
}
|
||||
|
||||
// Credit: http://stackoverflow.com/a/4694816/2087442
|
||||
function is_valid_domain_name($domain_name)
|
||||
{
|
||||
return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
|
||||
&& preg_match("/^.{1,253}$/", $domain_name) //overall length check
|
||||
&& preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name) ); //length of each label
|
||||
}
|
||||
|
||||
// Test if domain is set
|
||||
if(isset($_GET["domain"]))
|
||||
{
|
||||
// Is this a valid domain?
|
||||
$url = $_GET["domain"];
|
||||
if(!is_valid_domain_name($url))
|
||||
{
|
||||
echoEvent("Invalid domain!");
|
||||
die();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echoEvent("No domain provided");
|
||||
die();
|
||||
}
|
||||
|
||||
if(isset($_GET["exact"]))
|
||||
{
|
||||
$exact = "-exact";
|
||||
}
|
||||
else
|
||||
{
|
||||
$exact = "";
|
||||
}
|
||||
|
||||
$proc = popen("sudo pihole -q ".$url." ".$exact, 'r');
|
||||
while (!feof($proc)) {
|
||||
echoEvent(fread($proc, 4096));
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
|
||||
if(basename($_SERVER['SCRIPT_FILENAME']) !== "settings.php")
|
||||
{
|
||||
die("Direct access to this script is forbidden!");
|
||||
}
|
||||
|
||||
function validIP($address){
|
||||
return !filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false;
|
||||
}
|
||||
|
||||
// Check for existance of variable
|
||||
// and test it only if it exists
|
||||
function istrue(&$argument) {
|
||||
$ret = false;
|
||||
if(isset($argument))
|
||||
{
|
||||
if($argument)
|
||||
{
|
||||
$ret = true;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Credit: http://stackoverflow.com/a/4694816/2087442
|
||||
function validDomain($domain_name)
|
||||
{
|
||||
$validChars = preg_match("/^([_a-z\d](-*[_a-z\d])*)(\.([_a-z\d](-*[a-z\d])*))*(\.([a-z\d])*)*$/i", $domain_name);
|
||||
$lengthCheck = preg_match("/^.{1,253}$/", $domain_name);
|
||||
$labelLengthCheck = preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name);
|
||||
return ( $validChars && $lengthCheck && $labelLengthCheck ); //length of each label
|
||||
}
|
||||
|
||||
$primaryDNSservers = [
|
||||
"8.8.8.8" => "Google",
|
||||
"208.67.222.222" => "OpenDNS",
|
||||
"4.2.2.1" => "Level3",
|
||||
"199.85.126.10" => "Norton",
|
||||
"8.26.56.26" => "Comodo"
|
||||
];
|
||||
|
||||
$secondaryDNSservers = [
|
||||
"8.8.4.4" => "Google",
|
||||
"208.67.220.220" => "OpenDNS",
|
||||
"4.2.2.2" => "Level3",
|
||||
"199.85.127.10" => "Norton",
|
||||
"8.20.247.20" => "Comodo"
|
||||
];
|
||||
|
||||
$error = "";
|
||||
$success = "";
|
||||
|
||||
if(isset($_POST["field"]))
|
||||
{
|
||||
// Process request
|
||||
switch ($_POST["field"]) {
|
||||
// Set DNS server
|
||||
case "DNS":
|
||||
$primaryDNS = $_POST["primaryDNS"];
|
||||
$secondaryDNS = $_POST["secondaryDNS"];
|
||||
|
||||
// Get primary DNS server IP address
|
||||
if($primaryDNS === "Custom")
|
||||
{
|
||||
$primaryIP = $_POST["DNS1IP"];
|
||||
}
|
||||
else
|
||||
{
|
||||
$primaryIP = array_flip($primaryDNSservers)[$primaryDNS];
|
||||
}
|
||||
|
||||
// Validate primary IP
|
||||
if (!validIP($primaryIP))
|
||||
{
|
||||
$error .= "Primary IP (".$primaryIP.") is invalid!<br>";
|
||||
}
|
||||
|
||||
// Get secondary DNS server IP address
|
||||
if($secondaryDNS === "Custom")
|
||||
{
|
||||
if(strlen($_POST["DNS2IP"]) > 0)
|
||||
{
|
||||
$secondaryIP = $_POST["DNS2IP"];
|
||||
}
|
||||
else
|
||||
{
|
||||
$secondaryIP = "none";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$secondaryIP = array_flip($secondaryDNSservers)[$secondaryDNS];
|
||||
}
|
||||
|
||||
// Validate secondary IP
|
||||
if (!validIP($secondaryIP) && $secondaryIP != "none" && strlen($secondaryIP) > 0)
|
||||
{
|
||||
$error .= "Secondary IP (".$secondaryIP.") is invalid!<br>";
|
||||
}
|
||||
|
||||
// Check if domain-needed is requested
|
||||
if(isset($_POST["DNSrequiresFQDN"]))
|
||||
{
|
||||
$extra = "domain-needed ";
|
||||
}
|
||||
else
|
||||
{
|
||||
$extra = "domain-not-needed ";
|
||||
}
|
||||
|
||||
// Check if domain-needed is requested
|
||||
if(isset($_POST["DNSbogusPriv"]))
|
||||
{
|
||||
$extra .= "bogus-priv";
|
||||
}
|
||||
else
|
||||
{
|
||||
$extra .= "no-bogus-priv";
|
||||
}
|
||||
|
||||
// If there has been no error we can save the new DNS server IPs
|
||||
if(!strlen($error))
|
||||
{
|
||||
exec("sudo pihole -a setdns ".$primaryIP." ".$secondaryIP." ".$extra);
|
||||
$success .= "The DNS settings have been updated";
|
||||
}
|
||||
else
|
||||
{
|
||||
$error .= "The settings have been reset to their previous values";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Set query logging
|
||||
case "Logging":
|
||||
|
||||
if($_POST["action"] === "Disable")
|
||||
{
|
||||
exec("sudo pihole -l off");
|
||||
$success .= "Logging has been disabled";
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("sudo pihole -l on");
|
||||
$success .= "Logging has been enabled";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Set domains to be excluded from being shown in Top Domains (or Ads) and Top Clients
|
||||
case "API":
|
||||
|
||||
// Explode the contents of the textareas into PHP arrays
|
||||
// \n (Unix) and \r\n (Win) will be considered as newline
|
||||
// array_filter( ... ) will remove any empty lines
|
||||
$domains = array_filter(preg_split('/\r\n|[\r\n]/', $_POST["domains"]));
|
||||
$clients = array_filter(preg_split('/\r\n|[\r\n]/', $_POST["clients"]));
|
||||
|
||||
$domainlist = "";
|
||||
$first = true;
|
||||
foreach($domains as $domain)
|
||||
{
|
||||
if(!validDomain($domain))
|
||||
{
|
||||
$error .= "Top Domains/Ads entry ".$domain." is invalid!<br>";
|
||||
}
|
||||
if(!$first)
|
||||
{
|
||||
$domainlist .= ",";
|
||||
}
|
||||
else
|
||||
{
|
||||
$first = false;
|
||||
}
|
||||
$domainlist .= $domain;
|
||||
}
|
||||
|
||||
$clientlist = "";
|
||||
$first = true;
|
||||
foreach($clients as $client)
|
||||
{
|
||||
if(!validIP($client))
|
||||
{
|
||||
$error .= "Top Clients entry ".$client." is invalid (use only IP addresses)!<br>";
|
||||
}
|
||||
if(!$first)
|
||||
{
|
||||
$clientlist .= ",";
|
||||
}
|
||||
else
|
||||
{
|
||||
$first = false;
|
||||
}
|
||||
$clientlist .= $client;
|
||||
}
|
||||
|
||||
// Set Top Lists options
|
||||
if(!strlen($error))
|
||||
{
|
||||
// All entries are okay
|
||||
exec("sudo pihole -a setexcludedomains ".$domainlist);
|
||||
exec("sudo pihole -a setexcludeclients ".$clientlist);
|
||||
$success .= "The API settings have been updated<br>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$error .= "The settings have been reset to their previous values";
|
||||
}
|
||||
|
||||
// Set query log options
|
||||
if(isset($_POST["querylog-permitted"]) && isset($_POST["querylog-blocked"]))
|
||||
{
|
||||
exec("sudo pihole -a setquerylog all");
|
||||
if(!isset($_POST["privacyMode"]))
|
||||
{
|
||||
$success .= "All entries will be shown in Query Log";
|
||||
}
|
||||
else
|
||||
{
|
||||
$success .= "Only blocked entries will be shown in Query Log";
|
||||
}
|
||||
}
|
||||
elseif(isset($_POST["querylog-permitted"]))
|
||||
{
|
||||
exec("sudo pihole -a setquerylog permittedonly");
|
||||
if(!isset($_POST["privacyMode"]))
|
||||
{
|
||||
$success .= "Only permitted will be shown in Query Log";
|
||||
}
|
||||
else
|
||||
{
|
||||
$success .= "No entries will be shown in Query Log";
|
||||
}
|
||||
}
|
||||
elseif(isset($_POST["querylog-blocked"]))
|
||||
{
|
||||
exec("sudo pihole -a setquerylog blockedonly");
|
||||
$success .= "Only blocked entries will be shown in Query Log";
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("sudo pihole -a setquerylog nothing");
|
||||
$success .= "No entries will be shown in Query Log";
|
||||
}
|
||||
|
||||
|
||||
if(isset($_POST["privacyMode"]))
|
||||
{
|
||||
exec("sudo pihole -a privacymode true");
|
||||
$success .= " (privacy mode enabled)";
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("sudo pihole -a privacymode false");
|
||||
}
|
||||
|
||||
if(isset($_POST["resolve-forward"]))
|
||||
{
|
||||
exec("sudo pihole -a resolve forward true");
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("sudo pihole -a resolve forward false");
|
||||
}
|
||||
|
||||
if(isset($_POST["resolve-clients"]))
|
||||
{
|
||||
exec("sudo pihole -a resolve clients true");
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("sudo pihole -a resolve clients false");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "webUI":
|
||||
if($_POST["tempunit"] == "F")
|
||||
{
|
||||
exec('sudo pihole -a -f');
|
||||
}
|
||||
elseif($_POST["tempunit"] == "K")
|
||||
{
|
||||
exec('sudo pihole -a -k');
|
||||
}
|
||||
else
|
||||
{
|
||||
exec('sudo pihole -a -c');
|
||||
}
|
||||
if(isset($_POST["boxedlayout"]))
|
||||
{
|
||||
exec('sudo pihole -a layout boxed');
|
||||
}
|
||||
else
|
||||
{
|
||||
exec('sudo pihole -a layout traditional');
|
||||
}
|
||||
$success .= "The webUI settings have been updated";
|
||||
break;
|
||||
|
||||
case "reboot":
|
||||
exec("sudo pihole -a reboot");
|
||||
$success = "The system will reboot in 5 seconds...";
|
||||
break;
|
||||
|
||||
case "restartdns":
|
||||
exec("sudo pihole -a restartdns");
|
||||
$success = "The DNS server has been restarted";
|
||||
break;
|
||||
|
||||
case "flushlogs":
|
||||
exec("sudo pihole -f");
|
||||
$success = "The Pi-Hole log file has been flushed";
|
||||
break;
|
||||
|
||||
case "DHCP":
|
||||
|
||||
if(isset($_POST["active"]))
|
||||
{
|
||||
// Validate from IP
|
||||
$from = $_POST["from"];
|
||||
if (!validIP($from))
|
||||
{
|
||||
$error .= "From IP (".$from.") is invalid!<br>";
|
||||
}
|
||||
|
||||
// Validate to IP
|
||||
$to = $_POST["to"];
|
||||
if (!validIP($to))
|
||||
{
|
||||
$error .= "To IP (".$to.") is invalid!<br>";
|
||||
}
|
||||
|
||||
// Validate router IP
|
||||
$router = $_POST["router"];
|
||||
if (!validIP($router))
|
||||
{
|
||||
$error .= "Router IP (".$router.") is invalid!<br>";
|
||||
}
|
||||
|
||||
$domain = $_POST["domain"];
|
||||
|
||||
// Validate Domain name
|
||||
if(!validDomain($domain))
|
||||
{
|
||||
$error .= "Domain name ".$domain." is invalid!<br>";
|
||||
}
|
||||
|
||||
if(!strlen($error))
|
||||
{
|
||||
exec("sudo pihole -a enabledhcp ".$from." ".$to." ".$router);
|
||||
exec("sudo pihole -a domainname ".$domain);
|
||||
$success .= "The DHCP server has been activated";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exec("sudo pihole -a disabledhcp");
|
||||
$success = "The DHCP server has been deactivated";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Option not found
|
||||
$debug = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Credit: http://stackoverflow.com/a/5501447/2087442
|
||||
function formatSizeUnits($bytes)
|
||||
{
|
||||
if ($bytes >= 1073741824)
|
||||
{
|
||||
$bytes = number_format($bytes / 1073741824, 2) . ' GB';
|
||||
}
|
||||
elseif ($bytes >= 1048576)
|
||||
{
|
||||
$bytes = number_format($bytes / 1048576, 2) . ' MB';
|
||||
}
|
||||
elseif ($bytes >= 1024)
|
||||
{
|
||||
$bytes = number_format($bytes / 1024, 2) . ' kB';
|
||||
}
|
||||
elseif ($bytes > 1)
|
||||
{
|
||||
$bytes = $bytes . ' bytes';
|
||||
}
|
||||
elseif ($bytes == 1)
|
||||
{
|
||||
$bytes = $bytes . ' byte';
|
||||
}
|
||||
else
|
||||
{
|
||||
$bytes = '0 bytes';
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
require('auth.php');
|
||||
|
||||
$type = $_POST['list'];
|
||||
|
||||
// All of the verification for list editing
|
||||
list_verify($type);
|
||||
|
||||
switch($type) {
|
||||
case "white":
|
||||
exec("sudo pihole -w -q -d ${_POST['domain']}");
|
||||
break;
|
||||
case "black":
|
||||
exec("sudo pihole -b -q -d ${_POST['domain']}");
|
||||
break;
|
||||
}
|
||||
|
||||
?>
|
||||
Vendored
+15
File diff suppressed because one or more lines are too long
Vendored
+13
File diff suppressed because one or more lines are too long
+8
@@ -0,0 +1,8 @@
|
||||
/*!
|
||||
DataTables Bootstrap 3 integration
|
||||
©2011-2015 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
(function(b){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return b(a,window,document)}):"object"===typeof exports?module.exports=function(a,d){a||(a=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(a,d).$;return b(d,a,a.document)}:b(jQuery,window,document)})(function(b,a,d){var f=b.fn.dataTable;b.extend(!0,f.defaults,{dom:"<'row'<'col-sm-6'l><'col-sm-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-5'i><'col-sm-7'p>>",renderer:"bootstrap"});b.extend(f.ext.classes,
|
||||
{sWrapper:"dataTables_wrapper form-inline dt-bootstrap",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm",sProcessing:"dataTables_processing panel panel-default"});f.ext.renderer.pageButton.bootstrap=function(a,h,r,m,j,n){var o=new f.Api(a),s=a.oClasses,k=a.oLanguage.oPaginate,t=a.oLanguage.oAria.paginate||{},e,g,p=0,q=function(d,f){var l,h,i,c,m=function(a){a.preventDefault();!b(a.currentTarget).hasClass("disabled")&&o.page()!=a.data.action&&o.page(a.data.action).draw("page")};
|
||||
l=0;for(h=f.length;l<h;l++)if(c=f[l],b.isArray(c))q(d,c);else{g=e="";switch(c){case "ellipsis":e="…";g="disabled";break;case "first":e=k.sFirst;g=c+(0<j?"":" disabled");break;case "previous":e=k.sPrevious;g=c+(0<j?"":" disabled");break;case "next":e=k.sNext;g=c+(j<n-1?"":" disabled");break;case "last":e=k.sLast;g=c+(j<n-1?"":" disabled");break;default:e=c+1,g=j===c?"active":""}e&&(i=b("<li>",{"class":s.sPageButton+" "+g,id:0===r&&"string"===typeof c?a.sTableId+"_"+c:null}).append(b("<a>",{href:"#",
|
||||
"aria-controls":a.sTableId,"aria-label":t[c],"data-dt-idx":p,tabindex:a.iTabIndex}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(u){}q(b(h).empty().html('<ul class="pagination"/>').children("ul"),m);i&&b(h).find("[data-dt-idx="+i+"]").focus()};return f});
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);
|
||||
Vendored
+13
File diff suppressed because one or more lines are too long
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
/*!
|
||||
* jquery.confirm
|
||||
*
|
||||
* @version 2.3.1
|
||||
*
|
||||
* @author My C-Labs
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
* @author Russel Vela
|
||||
* @author Marcus Schwarz <msspamfang@gmx.de>
|
||||
*
|
||||
* @license MIT
|
||||
* @url https://myclabs.github.io/jquery.confirm/
|
||||
*/
|
||||
(function(a){a.fn.confirm=function(b){if(typeof b==="undefined"){b={}}this.click(function(c){c.preventDefault();var d=a.extend({button:a(this)},b);a.confirm(d,c)});return this};a.confirm=function(k,g){if(typeof k=="undefined"){console.error("No options given.");return}if(a(".confirmation-modal").length>0){return}var j={};if(k.button){var c={title:"title",text:"text","confirm-button":"confirmButton","submit-form":"submitForm","cancel-button":"cancelButton","confirm-button-class":"confirmButtonClass","cancel-button-class":"cancelButtonClass","dialog-class":"dialogClass","modal-options-backdrop":"modalOptionsBackdrop","modal-options-keyboard":"modalOptionsKeyboard"};a.each(c,function(e,l){var m=k.button.data(e);if(typeof m!="undefined"){j[l]=m}})}var d=a.extend({},a.confirm.options,{confirm:function(){if(j.submitForm||(typeof j.submitForm=="undefined"&&k.submitForm)||(typeof j.submitForm=="undefined"&&typeof k.submitForm=="undefined"&&a.confirm.options.submitForm)){g.target.closest("form").submit()}else{var e=g&&(("string"===typeof g&&g)||(g.currentTarget&&g.currentTarget.attributes.href.value));if(e){if(k.post){var l=a('<form method="post" class="hide" action="'+e+'"></form>');a("body").append(l);l.submit()}else{window.location=e}}}},cancel:function(e){},button:null},k,j);var b="";if(d.title!==""){b='<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h4 class="modal-title">'+d.title+"</h4></div>"}var h="";if(d.cancelButton){h='<button class="cancel btn '+d.cancelButtonClass+'" type="button" data-dismiss="modal">'+d.cancelButton+"</button>"}var f='<div class="confirmation-modal modal fade" tabindex="-1" role="dialog"><div class="'+d.dialogClass+'"><div class="modal-content">'+b+'<div class="modal-body">'+d.text+'</div><div class="modal-footer"><button class="confirm btn '+d.confirmButtonClass+'" type="button" data-dismiss="modal">'+d.confirmButton+"</button>"+h+"</div></div></div></div>";var i=a(f);if(typeof d.modalOptionsBackdrop!="undefined"||typeof d.modalOptionsKeyboard!="undefined"){i.modal({backdrop:d.modalOptionsBackdrop,keyboard:d.modalOptionsKeyboard})}i.on("shown.bs.modal",function(){i.find(".btn-primary:first").focus()});i.on("hidden.bs.modal",function(){i.remove()});i.find(".confirm").click(function(){d.confirm(d.button)});i.find(".cancel").click(function(){d.cancel(d.button)});a("body").append(i);i.modal("show")};a.confirm.options={text:"Are you sure?",title:"",confirmButton:"Yes",cancelButton:"Cancel",post:false,submitForm:false,confirmButtonClass:"btn-primary",cancelButtonClass:"btn-default",dialogClass:"modal-dialog",modalOptionsBackdrop:true,modalOptionsKeyboard:true}})(jQuery);
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/*!
|
||||
DataTables 1.10.12
|
||||
©2008-2015 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
(function(h){"function"===typeof define&&define.amd?define(["jquery"],function(D){return h(D,window,document)}):"object"===typeof exports?module.exports=function(D,I){D||(D=window);I||(I="undefined"!==typeof window?require("jquery"):require("jquery")(D));return h(I,D,D.document)}:h(jQuery,window,document)})(function(h,D,I,k){function X(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
|
||||
d[c]=e,"o"===b[1]&&X(a[e])});a._hungarianMap=d}function K(a,b,c){a._hungarianMap||X(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),K(a[d],b[d],c)):b[d]=b[e]})}function Da(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&E(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&E(a,a,"sZeroRecords","sLoadingRecords");
|
||||
a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&db(a)}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX=
|
||||
a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&K(m.models.oSearch,a[b])}function fb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function gb(a){if(!m.__browser){var b={};m.__browser=b;var c=h("<div/>").css({position:"fixed",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",top:1,left:1,
|
||||
width:100,overflow:"scroll"}).append(h("<div/>").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,m.__browser);a.oScroll.iBarWidth=m.__browser.barWidth}function hb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!==e;)a.hasOwnProperty(d)&&
|
||||
(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Ea(a,b){var c=m.defaults.column,d=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:I.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},m.models.oSearch,c[d]);ja(a,d,h(b).data())}function ja(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=e.attr("width")||null;var f=
|
||||
(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(fb(c),K(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),h.extend(b,c),E(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),E(b,c,"aDataSort"));var g=b.mData,j=Q(g),i=b.mRender?Q(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&
|
||||
(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return R(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):
|
||||
!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function Y(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Fa(a);for(var c=0,d=b.length;c<d;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&ka(a);u(a,null,"column-sizing",[a])}function Z(a,b){var c=la(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=la(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}
|
||||
function aa(a){var b=0;h.each(a.aoColumns,function(a,d){d.bVisible&&"none"!==h(d.nTh).css("display")&&b++});return b}function la(a,b){var c=[];h.map(a.aoColumns,function(a,e){a[b]&&c.push(e)});return c}function Ga(a){var b=a.aoColumns,c=a.aoData,d=m.ext.type.detect,e,f,g,j,i,h,l,q,t;e=0;for(f=b.length;e<f;e++)if(l=b[e],t=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=d.length;g<j;g++){i=0;for(h=c.length;i<h;i++){t[i]===k&&(t[i]=B(a,i,e,"type"));q=d[g](t[i],a);if(!q&&
|
||||
g!==d.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function ib(a,b,c,d){var e,f,g,j,i,n,l=a.aoColumns;if(b)for(e=b.length-1;0<=e;e--){n=b[e];var q=n.targets!==k?n.targets:n.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Ea(a);d(q[f],n)}else if("number"===typeof q[f]&&0>q[f])d(l.length+q[f],n);else if("string"===typeof q[f]){j=0;for(i=l.length;j<i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&
|
||||
d(j,n)}}if(c){e=0;for(a=c.length;e<a;e++)d(e,c[e])}}function N(a,b,c,d){var e=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data",idx:e});f._aData=b;a.aoData.push(f);for(var g=a.aoColumns,j=0,i=g.length;j<i;j++)g[j].sType=null;a.aiDisplayMaster.push(e);b=a.rowIdFn(b);b!==k&&(a.aIds[b]=f);(c||!a.oFeatures.bDeferRender)&&Ha(a,e,c,d);return e}function ma(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,e){c=Ia(a,e);return N(a,c.data,e,c.cells)})}function B(a,b,c,d){var e=a.iDraw,
|
||||
f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,i=f.fnGetData(g,d,{settings:a,row:b,col:c});if(i===k)return a.iDrawError!=e&&null===j&&(L(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b+", column "+c,4),a.iDrawError=e),j;if((i===g||null===i)&&null!==j&&d!==k)i=j;else if("function"===typeof i)return i.call(g);return null===i&&"display"==d?"":i}function jb(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,d,{settings:a,row:b,col:c})}
|
||||
function Ja(a){return h.map(a.match(/(\\.|[^\.])+/g)||[""],function(a){return a.replace(/\\./g,".")})}function Q(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=Q(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var g,j;if(""!==f){j=Ja(f);
|
||||
for(var i=0,n=j.length;i<n;i++){f=j[i].match(ba);g=j[i].match(U);if(f){j[i]=j[i].replace(ba,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");if(h.isArray(a)){i=0;for(n=a.length;i<n;i++)g.push(c(a[i],b,j))}a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(U,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===k)return k;a=a[j[i]]}}return a};return function(b,e){return c(b,e,a)}}return function(b){return b[a]}}function R(a){if(h.isPlainObject(a))return R(a._);
|
||||
if(null===a)return function(){};if("function"===typeof a)return function(b,d,e){a(b,"set",d,e)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,d,e){var e=Ja(e),f;f=e[e.length-1];for(var g,j,i=0,n=e.length-1;i<n;i++){g=e[i].match(ba);j=e[i].match(U);if(g){e[i]=e[i].replace(ba,"");a[e[i]]=[];f=e.slice();f.splice(0,i+1);g=f.join(".");if(h.isArray(d)){j=0;for(n=d.length;j<n;j++)f={},b(f,d[j],g),a[e[i]].push(f)}else a[e[i]]=d;return}j&&(e[i]=e[i].replace(U,
|
||||
""),a=a[e[i]](d));if(null===a[e[i]]||a[e[i]]===k)a[e[i]]={};a=a[e[i]]}if(f.match(U))a[f.replace(U,"")](d);else a[f.replace(ba,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Ka(a){return G(a.aoData,"_aData")}function na(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0;a.aIds={}}function oa(a,b,c){for(var d=-1,e=0,f=a.length;e<f;e++)a[e]==b?d=e:a[e]>b&&a[e]--; -1!=d&&c===k&&a.splice(d,1)}function ca(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild);
|
||||
c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ia(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}e._aSortData=null;e._aFilterData=null;g=a.aoColumns;if(d!==k)g[d].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;La(a,e)}}function Ia(a,b,c,d){var e=[],f=b.firstChild,g,j,i=0,n,l=a.aoColumns,q=a._rowReadObject,d=d!==k?d:q?{}:[],t=function(a,b){if("string"===typeof a){var c=a.indexOf("@");
|
||||
-1!==c&&(c=a.substring(c+1),R(a)(d,b.getAttribute(c)))}},S=function(a){if(c===k||c===i)j=l[i],n=h.trim(a.innerHTML),j&&j._bAttrSrc?(R(j.mData._)(d,n),t(j.mData.sort,a),t(j.mData.type,a),t(j.mData.filter,a)):q?(j._setter||(j._setter=R(j.mData)),j._setter(d,n)):d[i]=n;i++};if(f)for(;f;){g=f.nodeName.toUpperCase();if("TD"==g||"TH"==g)S(f),e.push(f);f=f.nextSibling}else{e=b.anCells;f=0;for(g=e.length;f<g;f++)S(e[f])}if(b=b.firstChild?b:b.nTr)(b=b.getAttribute("id"))&&R(a.rowId)(d,b);return{data:d,cells:e}}
|
||||
function Ha(a,b,c,d){var e=a.aoData[b],f=e._aData,g=[],j,i,n,l,q;if(null===e.nTr){j=c||I.createElement("tr");e.nTr=j;e.anCells=g;j._DT_RowIndex=b;La(a,e);l=0;for(q=a.aoColumns.length;l<q;l++){n=a.aoColumns[l];i=c?d[l]:I.createElement(n.sCellType);i._DT_CellIndex={row:b,column:l};g.push(i);if((!c||n.mRender||n.mData!==l)&&(!h.isPlainObject(n.mData)||n.mData._!==l+".display"))i.innerHTML=B(a,b,l,"display");n.sClass&&(i.className+=" "+n.sClass);n.bVisible&&!c?j.appendChild(i):!n.bVisible&&c&&i.parentNode.removeChild(i);
|
||||
n.fnCreatedCell&&n.fnCreatedCell.call(a.oInstance,i,B(a,b,l),f,b,l)}u(a,"aoRowCreatedCallback",null,[j,f,b])}e.nTr.setAttribute("role","row")}function La(a,b){var c=b.nTr,d=b._aData;if(c){var e=a.rowIdFn(d);e&&(c.id=e);d.DT_RowClass&&(e=d.DT_RowClass.split(" "),b.__rowc=b.__rowc?pa(b.__rowc.concat(e)):e,h(c).removeClass(b.__rowc.join(" ")).addClass(d.DT_RowClass));d.DT_RowAttr&&h(c).attr(d.DT_RowAttr);d.DT_RowData&&h(c).data(d.DT_RowData)}}function kb(a){var b,c,d,e,f,g=a.nTHead,j=a.nTFoot,i=0===
|
||||
h("th, td",g).length,n=a.oClasses,l=a.aoColumns;i&&(e=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],d=h(f.nTh).addClass(f.sClass),i&&d.appendTo(e),a.oFeatures.bSort&&(d.addClass(f.sSortingClass),!1!==f.bSortable&&(d.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Ma(a,f.nTh,b))),f.sTitle!=d[0].innerHTML&&d.html(f.sTitle),Na(a,"header")(a,d,f,n);i&&da(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(n.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(n.sFooterTH);
|
||||
if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var d,e,f,g=[],j=[],i=a.aoColumns.length,n;if(b){c===k&&(c=!1);d=0;for(e=b.length;d<e;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[d].splice(f,1);j.push([])}d=0;for(e=g.length;d<e;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(n=i=1,j[d][f]===k){a.appendChild(g[d][f].cell);
|
||||
for(j[d][f]=1;g[d+i]!==k&&g[d][f].cell==g[d+i][f].cell;)j[d+i][f]=1,i++;for(;g[d][f+n]!==k&&g[d][f].cell==g[d][f+n].cell;){for(c=0;c<i;c++)j[d+c][f+n]=1;n++}h(g[d][f].cell).attr("rowspan",i).attr("colspan",n)}}}}function O(a){var b=u(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,d=a.asStripeClasses,e=d.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==y(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=
|
||||
-1);var g=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!lb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:n;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ha(a,l);l=q.nTr;if(0!==e){var t=d[c%e];q._sRowStripe!=t&&(h(l).removeClass(q._sRowStripe).addClass(t),q._sRowStripe=t)}u(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,1==a.iDraw&&"ajax"==y(a)?c=f.sLoadingRecords:
|
||||
f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":e?d[0]:""}).append(h("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];u(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ka(a),g,n,i]);u(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ka(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));u(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function T(a,b){var c=a.oFeatures,d=c.bFilter;
|
||||
c.bSort&&mb(a);d?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;O(a);a._drawHold=!1}function nb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),d=a.oFeatures,e=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,t=0;t<f.length;t++){g=null;j=f[t];if("<"==j){i=h("<div/>")[0];
|
||||
n=f[t+1];if("'"==n||'"'==n){l="";for(q=2;f[t+q]!=n;)l+=f[t+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;t+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=ob(a);else if("f"==j&&d.bFilter)g=pb(a);else if("r"==j&&d.bProcessing)g=qb(a);else if("t"==j)g=rb(a);else if("i"==j&&d.bInfo)g=sb(a);else if("p"==
|
||||
j&&d.bPaginate)g=tb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q<n;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),e.append(g))}c.replaceWith(e);a.nHolding=null}function da(a,b){var c=h(b).children("tr"),d,e,f,g,j,i,n,l,q,t;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){d=c[f];for(e=d.firstChild;e;){if("TD"==e.nodeName.toUpperCase()||"TH"==e.nodeName.toUpperCase()){l=1*e.getAttribute("colspan");
|
||||
q=1*e.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;n=g;t=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][n+j]={cell:e,unique:t},a[f+g].nTr=d}e=e.nextSibling}}}function qa(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,e=c.length;b<e;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function ra(a,b,c){u(a,"aoServerParams","serverParams",[b]);if(b&&h.isArray(b)){var d={},
|
||||
e=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(e);c?(c=c[0],d[c]||(d[c]=[]),d[c].push(b.value)):d[b.name]=b.value});b=d}var f,g=a.ajax,j=a.oInstance,i=function(b){u(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var n=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&n?n:h.extend(!0,b,n);delete g.data}n={data:b,success:function(b){var c=b.error||b.sError;c&&L(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,c){var d=u(a,null,"xhr",
|
||||
[a,null,a.jqXHR]);-1===h.inArray(!0,d)&&("parsererror"==c?L(a,0,"Invalid JSON response",1):4===b.readyState&&L(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;u(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(n,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(n,g)),g.data=f)}function lb(a){return a.bAjaxDataGet?(a.iDraw++,C(a,
|
||||
!0),ra(a,ub(a),function(b){vb(a,b)}),!1):!0}function ub(a){var b=a.aoColumns,c=b.length,d=a.oFeatures,e=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,n,l,q=V(a);g=a._iDisplayStart;i=!1!==d.bPaginate?a._iDisplayLength:-1;var k=function(a,b){j.push({name:a,value:b})};k("sEcho",a.iDraw);k("iColumns",c);k("sColumns",G(b,"sName").join(","));k("iDisplayStart",g);k("iDisplayLength",i);var S={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:e.sSearch,regex:e.bRegex}};for(g=0;g<c;g++)n=b[g],
|
||||
l=f[g],i="function"==typeof n.mData?"function":n.mData,S.columns.push({data:i,name:n.sName,searchable:n.bSearchable,orderable:n.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),k("mDataProp_"+g,i),d.bFilter&&(k("sSearch_"+g,l.sSearch),k("bRegex_"+g,l.bRegex),k("bSearchable_"+g,n.bSearchable)),d.bSort&&k("bSortable_"+g,n.bSortable);d.bFilter&&(k("sSearch",e.sSearch),k("bRegex",e.bRegex));d.bSort&&(h.each(q,function(a,b){S.order.push({column:b.col,dir:b.dir});k("iSortCol_"+a,b.col);k("sSortDir_"+
|
||||
a,b.dir)}),k("iSortingCols",q.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:S:b?j:S}function vb(a,b){var c=sa(a,b),d=b.sEcho!==k?b.sEcho:b.draw,e=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(d){if(1*d<a.iDraw)return;a.iDraw=1*d}na(a);a._iRecordsTotal=parseInt(e,10);a._iRecordsDisplay=parseInt(f,10);d=0;for(e=c.length;d<e;d++)N(a,c[d]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;O(a);a._bInitComplete||
|
||||
ta(a,b);a.bAjaxDataGet=!0;C(a,!1)}function sa(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?Q(c)(b):b}function pb(a){var b=a.oClasses,c=a.sTableId,d=a.oLanguage,e=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),f=function(){var b=!this.value?
|
||||
"":this.value;b!=e.sSearch&&(fa(a,{sSearch:b,bRegex:e.bRegex,bSmart:e.bSmart,bCaseInsensitive:e.bCaseInsensitive}),a._iDisplayStart=0,O(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===y(a)?400:0,i=h("input",b).val(e.sSearch).attr("placeholder",d.sSearchPlaceholder).bind("keyup.DT search.DT input.DT paste.DT cut.DT",g?Oa(f,g):f).bind("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==I.activeElement&&i.val(e.sSearch)}catch(d){}});
|
||||
return b[0]}function fa(a,b,c){var d=a.oPreviousSearch,e=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};Ga(a);if("ssp"!=y(a)){wb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<e.length;b++)xb(a,e[b].sSearch,b,e[b].bEscapeRegex!==k?!e[b].bEscapeRegex:e[b].bRegex,e[b].bSmart,e[b].bCaseInsensitive);yb(a)}else f(b);a.bFiltered=!0;u(a,null,"search",[a])}function yb(a){for(var b=
|
||||
m.ext.search,c=a.aiDisplay,d,e,f=0,g=b.length;f<g;f++){for(var j=[],i=0,n=c.length;i<n;i++)e=c[i],d=a.aoData[e],b[f](a,d._aFilterData,e,d._aData,i)&&j.push(e);c.length=0;h.merge(c,j)}}function xb(a,b,c,d,e,f){if(""!==b)for(var g=a.aiDisplay,d=Pa(b,d,e,f),e=g.length-1;0<=e;e--)b=a.aoData[g[e]]._aFilterData[c],d.test(b)||g.splice(e,1)}function wb(a,b,c,d,e,f){var d=Pa(b,d,e,f),e=a.oPreviousSearch.sSearch,f=a.aiDisplayMaster,g;0!==m.ext.search.length&&(c=!0);g=zb(a);if(0>=b.length)a.aiDisplay=f.slice();
|
||||
else{if(g||c||e.length>b.length||0!==b.indexOf(e)||a.bSorted)a.aiDisplay=f.slice();b=a.aiDisplay;for(c=b.length-1;0<=c;c--)d.test(a.aoData[b[c]]._sFilterRow)||b.splice(c,1)}}function Pa(a,b,c,d){a=b?a:Qa(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,d?"i":"")}function zb(a){var b=a.aoColumns,c,d,e,f,g,j,i,h,l=m.ext.type.search;c=!1;d=0;for(f=a.aoData.length;d<
|
||||
f;d++)if(h=a.aoData[d],!h._aFilterData){j=[];e=0;for(g=b.length;e<g;e++)c=b[e],c.bSearchable?(i=B(a,d,e,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(ua.innerHTML=i,i=Zb?ua.textContent:ua.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join(" ");c=!0}return c}function Ab(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,caseInsensitive:a.bCaseInsensitive}}
|
||||
function Bb(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function sb(a){var b=a.sTableId,c=a.aanFeatures.i,d=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Cb,sName:"information"}),d.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return d[0]}function Cb(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,d=a._iDisplayStart+1,e=a.fnDisplayEnd(),f=a.fnRecordsTotal(),
|
||||
g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Db(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,d,e,f,g,j));h(b).html(j)}}function Db(a,b){var c=a.fnFormatNumber,d=a._iDisplayStart+1,e=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===e;return b.replace(/_START_/g,c.call(a,d)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(d/
|
||||
e))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/e)))}function ga(a){var b,c,d=a.iInitDisplayStart,e=a.aoColumns,f;c=a.oFeatures;var g=a.bDeferLoading;if(a.bInitialised){nb(a);kb(a);ea(a,a.aoHeader);ea(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Fa(a);b=0;for(c=e.length;b<c;b++)f=e[b],f.sWidth&&(f.nTh.style.width=x(f.sWidth));u(a,null,"preInit",[a]);T(a);e=y(a);if("ssp"!=e||g)"ajax"==e?ra(a,[],function(c){var f=sa(a,c);for(b=0;b<f.length;b++)N(a,f[b]);a.iInitDisplayStart=d;T(a);C(a,!1);ta(a,c)},a):(C(a,!1),
|
||||
ta(a))}else setTimeout(function(){ga(a)},200)}function ta(a,b){a._bInitComplete=!0;(b||a.oInit.aaData)&&Y(a);u(a,null,"plugin-init",[a,b]);u(a,"aoInitComplete","init",[a,b])}function Ra(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Sa(a);u(a,null,"length",[a,c])}function ob(a){for(var b=a.oClasses,c=a.sTableId,d=a.aLengthMenu,e=h.isArray(d[0]),f=e?d[0]:d,d=e?d[1]:d,e=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)e[0][g]=new Option(d[g],f[g]);var i=
|
||||
h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).bind("change.DT",function(){Ra(a,h(this).val());O(a)});h(a.nTable).bind("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function tb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){O(a)},b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;
|
||||
d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;l<k;l++)Na(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,e)},sName:"pagination"}));return b}function Ta(a,b,c){var d=a._iDisplayStart,e=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===e?d=0:"number"===typeof b?(d=b*e,d>f&&(d=0)):"first"==b?d=0:
|
||||
"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e<f&&(d+=e):"last"==b?d=Math.floor((f-1)/e)*e:L(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==d;a._iDisplayStart=d;b&&(u(a,null,"page",[a]),c&&O(a));return b}function qb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");u(a,null,"processing",
|
||||
[a,b])}function rb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:x(d):"100%"}).append(h("<div/>",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",
|
||||
width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:x(d)}).append(b));l&&i.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:x(d):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left",0).append("bottom"===j?g:null).append(b.children("tfoot")))));
|
||||
var b=i.children(),k=b[0],f=b[1],t=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(t.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=t;a.aoDrawCallback.push({fn:ka,sName:"scrolling"});return i[0]}function ka(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"),j=a.nScrollBody,l=h(j),q=j.style,t=h(a.nScrollFoot).children("div"),
|
||||
m=t.children("table"),o=h(a.nTHead),F=h(a.nTable),p=F[0],r=p.style,u=a.nTFoot?h(a.nTFoot):null,Eb=a.oBrowser,Ua=Eb.bScrollOversize,s=G(a.aoColumns,"nTh"),P,v,w,y,z=[],A=[],B=[],C=[],D,E=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};v=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==v&&a.scrollBarVis!==k)a.scrollBarVis=v,Y(a);else{a.scrollBarVis=v;F.children("thead, tfoot").remove();u&&(w=u.clone().prependTo(F),P=u.find("tr"),w=
|
||||
w.find("tr"));y=o.clone().prependTo(F);o=o.find("tr");v=y.find("tr");y.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(qa(a,y),function(b,c){D=Z(a,b);c.style.width=a.aoColumns[D].sWidth});u&&J(function(a){a.style.width=""},w);f=F.outerWidth();if(""===c){r.width="100%";if(Ua&&(F.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=x(F.outerWidth()-b);f=F.outerWidth()}else""!==d&&(r.width=x(d),f=F.outerWidth());J(E,v);J(function(a){B.push(a.innerHTML);
|
||||
z.push(x(h(a).css("width")))},v);J(function(a,b){if(h.inArray(a,s)!==-1)a.style.width=z[b]},o);h(v).height(0);u&&(J(E,w),J(function(a){C.push(a.innerHTML);A.push(x(h(a).css("width")))},w),J(function(a,b){a.style.width=A[b]},P),h(w).height(0));J(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+B[b]+"</div>";a.style.width=z[b]},v);u&&J(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+C[b]+"</div>";a.style.width=
|
||||
A[b]},w);if(F.outerWidth()<f){P=j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(Ua&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=x(P-b);(""===c||""!==d)&&L(a,1,"Possible column misalignment",6)}else P="100%";q.width=x(P);g.width=x(P);u&&(a.nScrollFoot.style.width=x(P));!e&&Ua&&(q.height=x(p.offsetHeight+b));c=F.outerWidth();n[0].style.width=x(c);i.width=x(c);d=F.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+(Eb.bScrollbarLeft?"Left":
|
||||
"Right");i[e]=d?b+"px":"0px";u&&(m[0].style.width=x(c),t[0].style.width=x(c),t[0].style[e]=d?b+"px":"0px");F.children("colgroup").insertBefore(F.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function J(a,b,c){for(var d=0,e=0,f=b.length,g,j;e<f;){g=b[e].firstChild;for(j=c?c[e].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,d):a(g,d),d++),g=g.nextSibling,j=c?j.nextSibling:null;e++}}function Fa(a){var b=a.nTable,c=a.aoColumns,d=a.oScroll,e=d.sY,f=d.sX,g=d.sXInner,
|
||||
j=c.length,i=la(a,"bVisible"),n=h("th",a.nTHead),l=b.getAttribute("width"),k=b.parentNode,t=!1,m,o,p=a.oBrowser,d=p.bScrollOversize;(m=b.style.width)&&-1!==m.indexOf("%")&&(l=m);for(m=0;m<i.length;m++)o=c[i[m]],null!==o.sWidth&&(o.sWidth=Fb(o.sWidthOrig,k),t=!0);if(d||!t&&!f&&!e&&j==aa(a)&&j==n.length)for(m=0;m<j;m++)i=Z(a,m),null!==i&&(c[i].sWidth=x(n.eq(m).width()));else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var r=h("<tr/>").appendTo(j.find("tbody"));
|
||||
j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=qa(a,j.find("thead")[0]);for(m=0;m<i.length;m++)o=c[i[m]],n[m].style.width=null!==o.sWidthOrig&&""!==o.sWidthOrig?x(o.sWidthOrig):"",o.sWidthOrig&&f&&h(n[m]).append(h("<div/>").css({width:o.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m<i.length;m++)t=i[m],o=c[t],h(Gb(a,t)).clone(!1).append(o.sContentPadding).appendTo(r);h("[name]",
|
||||
j).removeAttr("name");o=h("<div/>").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()<k.clientWidth&&l&&j.width(k.clientWidth)):e?j.width(k.clientWidth):l&&j.width(l);for(m=e=0;m<i.length;m++)k=h(n[m]),g=k.outerWidth()-k.width(),k=p.bBounding?Math.ceil(n[m].getBoundingClientRect().width):k.outerWidth(),e+=k,c[i[m]].sWidth=x(k-g);b.style.width=x(e);o.remove()}l&&(b.style.width=
|
||||
x(l));if((l||f)&&!a._reszEvt)b=function(){h(D).bind("resize.DT-"+a.sInstance,Oa(function(){Y(a)}))},d?setTimeout(b,1E3):b(),a._reszEvt=!0}function Fb(a,b){if(!a)return 0;var c=h("<div/>").css("width",x(a)).appendTo(b||I.body),d=c[0].offsetWidth;c.remove();return d}function Gb(a,b){var c=Hb(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("<td/>").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Hb(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;f<g;f++)c=B(a,f,b,"display")+"",c=c.replace($b,
|
||||
""),c=c.replace(/ /g," "),c.length>d&&(d=c.length,e=f);return e}function x(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function V(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<n.length;a++){i=n[a][0];f=e[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=e[g].sType||
|
||||
"string",n[a]._idx===k&&(n[a]._idx=h.inArray(n[a][1],e[g].asSorting)),d.push({src:i,col:g,dir:n[a][1],index:n[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return d}function mb(a){var b,c,d=[],e=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;Ga(a);h=V(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Ib(a,j.col);if("ssp"!=y(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)d[i[b]]=b;g===h.length?i.sort(function(a,b){var c,e,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=
|
||||
0;g<i;g++)if(j=h[g],c=k[j.col],e=m[j.col],c=c<e?-1:c>e?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return c<e?-1:c>e?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,p=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=p[i.col],i=e[i.type+"-"+i.dir]||e["string-"+i.dir],c=i(c,g),0!==c)return c;c=d[a];g=d[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Jb(a){for(var b,c,d=a.aoColumns,e=V(a),a=a.oLanguage.oAria,f=0,g=d.length;f<g;f++){c=d[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,
|
||||
"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<e.length&&e[0].col==f?(i.setAttribute("aria-sort","asc"==e[0].dir?"ascending":"descending"),c=j[e[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",b)}}function Va(a,b,c,d){var e=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof e[0]&&(e=a.aaSorting=[e]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,
|
||||
G(e,"0")),-1!==c?(b=g(e[c],!0),null===b&&1===e.length&&(b=0),null===b?e.splice(c,1):(e[c][1]=f[b],e[c]._idx=b)):(e.push([b,f[0],0]),e[e.length-1]._idx=0)):e.length&&e[0][0]==b?(b=g(e[0]),e.length=1,e[0][1]=f[b],e[0]._idx=b):(e.length=0,e.push([b,f[0]]),e[0]._idx=0);T(a);"function"==typeof d&&d(a)}function Ma(a,b,c,d){var e=a.aoColumns[c];Wa(b,{},function(b){!1!==e.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Va(a,c,b.shiftKey,d);"ssp"!==y(a)&&C(a,!1)},0)):Va(a,c,b.shiftKey,d))})}
|
||||
function va(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,d=V(a),e=a.oFeatures,f,g;if(e.bSort&&e.bSortClasses){e=0;for(f=b.length;e<f;e++)g=b[e].src,h(G(a.aoData,"anCells",g)).removeClass(c+(2>e?e+1:3));e=0;for(f=d.length;e<f;e++)g=d[e].src,h(G(a.aoData,"anCells",g)).addClass(c+(2>e?e+1:3))}a.aLastSort=d}function Ib(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],
|
||||
c._aSortData||(c._aSortData=[]),!c._aSortData[b]||d)f=d?e[j]:B(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function wa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),search:Ab(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,d){return{visible:b.bVisible,search:Ab(a.aoPreSearchCols[d])}})};u(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,
|
||||
b)}}function Kb(a){var b,c,d=a.aoColumns;if(a.oFeatures.bStateSave){var e=a.fnStateLoadCallback.call(a.oInstance,a);if(e&&e.time&&(b=u(a,"aoStateLoadParams","stateLoadParams",[a,e]),-1===h.inArray(!1,b)&&(b=a.iStateDuration,!(0<b&&e.time<+new Date-1E3*b)&&d.length===e.columns.length))){a.oLoadedState=h.extend(!0,{},e);e.start!==k&&(a._iDisplayStart=e.start,a.iInitDisplayStart=e.start);e.length!==k&&(a._iDisplayLength=e.length);e.order!==k&&(a.aaSorting=[],h.each(e.order,function(b,c){a.aaSorting.push(c[0]>=
|
||||
d.length?[0,c[1]]:c)}));e.search!==k&&h.extend(a.oPreviousSearch,Bb(e.search));b=0;for(c=e.columns.length;b<c;b++){var f=e.columns[b];f.visible!==k&&(d[b].bVisible=f.visible);f.search!==k&&h.extend(a.aoPreSearchCols[b],Bb(f.search))}u(a,"aoStateLoaded","stateLoaded",[a,e])}}}function xa(a){var b=m.settings,a=h.inArray(a,G(b,"nTable"));return-1!==a?b[a]:null}function L(a,b,c,d){c="DataTables warning: "+(a?"table id="+a.sTableId+" - ":"")+c;d&&(c+=". For more information about this error, please see http://datatables.net/tn/"+
|
||||
d);if(b)D.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,a&&u(a,null,"error",[a,d,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,d,c)}}function E(a,b,c,d){h.isArray(c)?h.each(c,function(c,d){h.isArray(d)?E(a,b,d[0],d[1]):E(a,b,d)}):(d===k&&(d=c),b[c]!==k&&(a[d]=b[c]))}function Lb(a,b,c){var d,e;for(e in b)b.hasOwnProperty(e)&&(d=b[e],h.isPlainObject(d)?(h.isPlainObject(a[e])||(a[e]={}),h.extend(!0,a[e],d)):a[e]=c&&"data"!==e&&"aaData"!==
|
||||
e&&h.isArray(d)?d.slice():d);return a}function Wa(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function u(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&(b=h.Event(c+".dt"),h(a.nTable).trigger(b,d),e.push(b.result));return e}function Sa(a){var b=a._iDisplayStart,
|
||||
c=a.fnDisplayEnd(),d=a._iDisplayLength;b>=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Na(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ya(a,b){var c=[],c=Mb.numbers_length,d=Math.floor(c/2);b<=c?c=W(0,b):a<=d?(c=W(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=W(b-(c-2),b):(c=W(a-d+2,a+d-1),c.push("ellipsis"),
|
||||
c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function db(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Xa)},"html-num":function(b){return za(b,a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Xa)}},function(b,c){v.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(v.type.search[b+a]=v.type.search.html)})}function Nb(a){return function(){var b=[xa(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,
|
||||
b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new r(xa(this[v.iApiIndex])):new r(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):
|
||||
(""!==d.sX||""!==d.sY)&&ka(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,
|
||||
c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),
|
||||
[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return xa(this[v.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=
|
||||
function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=v.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=v.internal;for(var e in m.ext.internal)e&&(this[e]=Nb(e));this.each(function(){var e={},e=1<d?Lb(e,a,!0):a,g=0,j,i=this.getAttribute("id"),n=!1,l=m.defaults,q=h(this);if("table"!=
|
||||
this.nodeName.toLowerCase())L(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{eb(l);fb(l.column);K(l,l,!0);K(l.column,l.column,!0);K(l,h.extend(e,q.data()));var t=m.settings,g=0;for(j=t.length;g<j;g++){var p=t[g];if(p.nTable==this||p.nTHead.parentNode==this||p.nTFoot&&p.nTFoot.parentNode==this){g=e.bRetrieve!==k?e.bRetrieve:l.bRetrieve;if(c||g)return p.oInstance;if(e.bDestroy!==k?e.bDestroy:l.bDestroy){p.oInstance.fnDestroy();break}else{L(p,0,"Cannot reinitialise DataTable",3);
|
||||
return}}if(p.sTableId==this.id){t.splice(g,1);break}}if(null===i||""===i)this.id=i="DataTables_Table_"+m.ext._unique++;var o=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:i,sTableId:i});o.nTable=this;o.oApi=b.internal;o.oInit=e;t.push(o);o.oInstance=1===b.length?b:q.dataTable();eb(e);e.oLanguage&&Da(e.oLanguage);e.aLengthMenu&&!e.iDisplayLength&&(e.iDisplayLength=h.isArray(e.aLengthMenu[0])?e.aLengthMenu[0][0]:e.aLengthMenu[0]);e=Lb(h.extend(!0,{},l),e);E(o.oFeatures,
|
||||
e,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));E(o,e,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback","renderer","searchDelay","rowId",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols",
|
||||
"aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);E(o.oScroll,e,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);E(o.oLanguage,e,"fnInfoCallback");z(o,"aoDrawCallback",e.fnDrawCallback,"user");z(o,"aoServerParams",e.fnServerParams,"user");z(o,"aoStateSaveParams",e.fnStateSaveParams,"user");z(o,"aoStateLoadParams",e.fnStateLoadParams,"user");z(o,"aoStateLoaded",e.fnStateLoaded,"user");z(o,"aoRowCallback",e.fnRowCallback,
|
||||
"user");z(o,"aoRowCreatedCallback",e.fnCreatedRow,"user");z(o,"aoHeaderCallback",e.fnHeaderCallback,"user");z(o,"aoFooterCallback",e.fnFooterCallback,"user");z(o,"aoInitComplete",e.fnInitComplete,"user");z(o,"aoPreDrawCallback",e.fnPreDrawCallback,"user");o.rowIdFn=Q(e.rowId);gb(o);i=o.oClasses;e.bJQueryUI?(h.extend(i,m.ext.oJUIClasses,e.oClasses),e.sDom===l.sDom&&"lfrtip"===l.sDom&&(o.sDom='<"H"lfr>t<"F"ip>'),o.renderer)?h.isPlainObject(o.renderer)&&!o.renderer.header&&(o.renderer.header="jqueryui"):
|
||||
o.renderer="jqueryui":h.extend(i,m.ext.classes,e.oClasses);q.addClass(i.sTable);o.iInitDisplayStart===k&&(o.iInitDisplayStart=e.iDisplayStart,o._iDisplayStart=e.iDisplayStart);null!==e.iDeferLoading&&(o.bDeferLoading=!0,g=h.isArray(e.iDeferLoading),o._iRecordsDisplay=g?e.iDeferLoading[0]:e.iDeferLoading,o._iRecordsTotal=g?e.iDeferLoading[1]:e.iDeferLoading);var r=o.oLanguage;h.extend(!0,r,e.oLanguage);""!==r.sUrl&&(h.ajax({dataType:"json",url:r.sUrl,success:function(a){Da(a);K(l.oLanguage,a);h.extend(true,
|
||||
r,a);ga(o)},error:function(){ga(o)}}),n=!0);null===e.asStripeClasses&&(o.asStripeClasses=[i.sStripeOdd,i.sStripeEven]);var g=o.asStripeClasses,v=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(g,function(a){return v.hasClass(a)}))&&(h("tbody tr",this).removeClass(g.join(" ")),o.asDestroyStripes=g.slice());t=[];g=this.getElementsByTagName("thead");0!==g.length&&(da(o.aoHeader,g[0]),t=qa(o));if(null===e.aoColumns){p=[];g=0;for(j=t.length;g<j;g++)p.push(null)}else p=e.aoColumns;g=0;for(j=
|
||||
p.length;g<j;g++)Ea(o,t?t[g]:null);ib(o,e.aoColumnDefs,p,function(a,b){ja(o,a,b)});if(v.length){var s=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h(v[0]).children("th, td").each(function(a,b){var c=o.aoColumns[a];if(c.mData===a){var d=s(b,"sort")||s(b,"order"),e=s(b,"filter")||s(b,"search");if(d!==null||e!==null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};ja(o,a)}}})}var w=o.oFeatures;e.bStateSave&&(w.bStateSave=
|
||||
!0,Kb(o,e),z(o,"aoDrawCallback",wa,"state_save"));if(e.aaSorting===k){t=o.aaSorting;g=0;for(j=t.length;g<j;g++)t[g][1]=o.aoColumns[g].asSorting[0]}va(o);w.bSort&&z(o,"aoDrawCallback",function(){if(o.bSorted){var a=V(o),b={};h.each(a,function(a,c){b[c.src]=c.dir});u(o,null,"order",[o,a,b]);Jb(o)}});z(o,"aoDrawCallback",function(){(o.bSorted||y(o)==="ssp"||w.bDeferRender)&&va(o)},"sc");g=q.children("caption").each(function(){this._captionSide=q.css("caption-side")});j=q.children("thead");0===j.length&&
|
||||
(j=h("<thead/>").appendTo(this));o.nTHead=j[0];j=q.children("tbody");0===j.length&&(j=h("<tbody/>").appendTo(this));o.nTBody=j[0];j=q.children("tfoot");if(0===j.length&&0<g.length&&(""!==o.oScroll.sX||""!==o.oScroll.sY))j=h("<tfoot/>").appendTo(this);0===j.length||0===j.children().length?q.addClass(i.sNoFooter):0<j.length&&(o.nTFoot=j[0],da(o.aoFooter,o.nTFoot));if(e.aaData)for(g=0;g<e.aaData.length;g++)N(o,e.aaData[g]);else(o.bDeferLoading||"dom"==y(o))&&ma(o,h(o.nTBody).children("tr"));o.aiDisplay=
|
||||
o.aiDisplayMaster.slice();o.bInitialised=!0;!1===n&&ga(o)}});b=null;return this},v,r,p,s,Ya={},Ob=/[\r\n]/g,Aa=/<.*?>/g,ac=/^[\w\+\-]/,bc=/[\w\+\-]$/,cc=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Xa=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,M=function(a){return!a||!0===a||"-"===a?!0:!1},Pb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Qb=function(a,b){Ya[b]||(Ya[b]=RegExp(Qa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,
|
||||
"").replace(Ya[b],"."):a},Za=function(a,b,c){var d="string"===typeof a;if(M(a))return!0;b&&d&&(a=Qb(a,b));c&&d&&(a=a.replace(Xa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Rb=function(a,b,c){return M(a)?!0:!(M(a)||"string"===typeof a)?null:Za(a.replace(Aa,""),b,c)?!0:null},G=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;e<f;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;e<f;e++)a[e]&&d.push(a[e][b]);return d},ha=function(a,b,c,d){var e=[],f=0,g=b.length;if(d!==k)for(;f<g;f++)a[b[f]][c]&&
|
||||
e.push(a[b[f]][c][d]);else for(;f<g;f++)e.push(a[b[f]][c]);return e},W=function(a,b){var c=[],d;b===k?(b=0,d=a):(d=b,b=a);for(var e=b;e<d;e++)c.push(e);return c},Sb=function(a){for(var b=[],c=0,d=a.length;c<d;c++)a[c]&&b.push(a[c]);return b},pa=function(a){var b=[],c,d,e=a.length,f,g=0;d=0;a:for(;d<e;d++){c=a[d];for(f=0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b};m.util={throttle:function(a,b){var c=b!==k?b:200,d,e;return function(){var b=this,g=+new Date,h=arguments;d&&g<d+c?(clearTimeout(e),
|
||||
e=setTimeout(function(){d=k;a.apply(b,h)},c)):(d=g,a.apply(b,h))}},escapeRegex:function(a){return a.replace(cc,"\\$1")}};var A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ba=/\[.*?\]$/,U=/\(\)$/,Qa=m.util.escapeRegex,ua=h("<div>")[0],Zb=ua.textContent!==k,$b=/<.*?>/g,Oa=m.util.throttle,Tb=[],w=Array.prototype,dc=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:
|
||||
null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};r=function(a,b){if(!(this instanceof r))return new r(a,b);var c=[],d=function(a){(a=dc(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;e<f;e++)d(a[e]);else d(a);this.context=pa(c);b&&h.merge(this,b);this.selector={rows:null,cols:null,opts:null};r.extend(this,this,Tb)};
|
||||
m.Api=r;h.extend(r.prototype,{any:function(){return 0!==this.count()},concat:w.concat,context:[],count:function(){return this.flatten().length},each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new r(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new r(this.context,b)},flatten:function(){var a=
|
||||
[];return new r(this.context,a.concat.apply(a,this.toArray()))},join:w.join,indexOf:w.indexOf||function(a,b){for(var c=b||0,d=this.length;c<d;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,d){var e=[],f,g,h,i,n,l=this.context,m,t,p=this.selector;"string"===typeof a&&(d=c,c=b,b=a,a=!1);g=0;for(h=l.length;g<h;g++){var o=new r(l[g]);if("table"===b)f=c.call(o,l[g],g),f!==k&&e.push(f);else if("columns"===b||"rows"===b)f=c.call(o,l[g],this[g],g),f!==k&&e.push(f);else if("column"===b||"column-rows"===
|
||||
b||"row"===b||"cell"===b){t=this[g];"column-rows"===b&&(m=Ba(l[g],p.opts));i=0;for(n=t.length;i<n;i++)f=t[i],f="cell"===b?c.call(o,l[g],f.row,f.column,g,i):c.call(o,l[g],f,g,i,m),f!==k&&e.push(f)}}return e.length||d?(a=new r(l,a?e.concat.apply([],e):e),b=a.selector,b.rows=p.rows,b.cols=p.cols,b.opts=p.opts,a):this},lastIndexOf:w.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(w.map)b=w.map.call(this,a,this);else for(var c=
|
||||
0,d=this.length;c<d;c++)b.push(a.call(this,this[c],c));return new r(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:w.pop,push:w.push,reduce:w.reduce||function(a,b){return hb(this,a,b,0,this.length,1)},reduceRight:w.reduceRight||function(a,b){return hb(this,a,b,this.length-1,-1,-1)},reverse:w.reverse,selector:null,shift:w.shift,sort:w.sort,splice:w.splice,toArray:function(){return w.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},
|
||||
unique:function(){return new r(this.context,pa(this))},unshift:w.unshift});r.extend=function(a,b,c){if(c.length&&b&&(b instanceof r||b.__dt_wrapper)){var d,e,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);r.extend(d,d,c.methodExt);return d}};d=0;for(e=c.length;d<e;d++)f=c[d],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,r.extend(a,b[f.name],f.propExt)}};r.register=p=function(a,b){if(h.isArray(a))for(var c=0,d=a.length;c<
|
||||
d;c++)r.register(a[c],b);else for(var e=a.split("."),f=Tb,g,j,c=0,d=e.length;c<d;c++){g=(j=-1!==e[c].indexOf("()"))?e[c].replace("()",""):e[c];var i;a:{i=0;for(var n=f.length;i<n;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===d-1?i.val=b:f=j?i.methodExt:i.propExt}};r.registerPlural=s=function(a,b,c){r.register(a,c);r.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof r?a.length?h.isArray(a[0])?new r(a.context,
|
||||
a[0]):a[0]:k:a})};p("tables()",function(a){var b;if(a){b=r;var c=this.context;if("number"===typeof a)a=[c[a]];else var d=h.map(c,function(a){return a.nTable}),a=h(d).filter(a).map(function(){var a=h.inArray(this,d);return c[a]}).toArray();b=new b(a)}else b=this;return b});p("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new r(b[0]):a});s("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});s("tables().body()","table().body()",
|
||||
function(){return this.iterator("table",function(a){return a.nTBody},1)});s("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});s("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});s("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});p("draw()",function(a){return this.iterator("table",function(b){"page"===
|
||||
a?O(b):("string"===typeof a&&(a="full-hold"===a?!1:!0),T(b,!1===a))})});p("page()",function(a){return a===k?this.page.info().page:this.iterator("table",function(b){Ta(b,a)})});p("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a.oFeatures.bPaginate?a._iDisplayLength:-1,d=a.fnRecordsDisplay(),e=-1===c;return{page:e?0:Math.floor(b/c),pages:e?1:Math.ceil(d/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:d,
|
||||
serverSide:"ssp"===y(a)}});p("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:k:this.iterator("table",function(b){Ra(b,a)})});var Ub=function(a,b,c){if(c){var d=new r(a);d.one("draw",function(){c(d.ajax.json())})}if("ssp"==y(a))T(a,b);else{C(a,!0);var e=a.jqXHR;e&&4!==e.readyState&&e.abort();ra(a,[],function(c){na(a);for(var c=sa(a,c),d=0,e=c.length;d<e;d++)N(a,c[d]);T(a,b);C(a,!1)})}};p("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});
|
||||
p("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});p("ajax.reload()",function(a,b){return this.iterator("table",function(c){Ub(c,!1===b,a)})});p("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});p("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Ub(c,
|
||||
!1===b,a)})});var $a=function(a,b,c,d,e){var f=[],g,j,i,n,l,m;i=typeof b;if(!b||"string"===i||"function"===i||b.length===k)b=[b];i=0;for(n=b.length;i<n;i++){j=b[i]&&b[i].split?b[i].split(","):[b[i]];l=0;for(m=j.length;l<m;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&(f=f.concat(g))}a=v.selector[a];if(a.length){i=0;for(n=a.length;i<n;i++)f=a[i](d,e,f)}return pa(f)},ab=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",
|
||||
page:"all"},a)},bb=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},Ba=function(a,b){var c,d,e,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;d=b.order;e=b.page;if("ssp"==y(a))return"removed"===j?[]:W(0,c.length);if("current"==e){c=a._iDisplayStart;for(d=a.fnDisplayEnd();c<d;c++)f.push(g[c])}else if("current"==d||"applied"==d)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===
|
||||
h.inArray(a,g)?a:null});else if("index"==d||"original"==d){c=0;for(d=a.aoData.length;c<d;c++)"none"==j?f.push(c):(e=h.inArray(c,g),(-1===e&&"removed"==j||0<=e&&"applied"==j)&&f.push(c))}return f};p("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var e=b;return $a("row",a,function(a){var b=Pb(a);if(b!==null&&!e)return[b];var j=Ba(c,e);if(b!==null&&h.inArray(b,j)!==-1)return[b];if(!a)return j;if(typeof a==="function")return h.map(j,function(b){var e=
|
||||
c.aoData[b];return a(b,e._aData,e.nTr)?b:null});b=Sb(ha(c.aoData,j,"nTr"));if(a.nodeName){if(a._DT_RowIndex!==k)return[a._DT_RowIndex];if(a._DT_CellIndex)return[a._DT_CellIndex.row];b=h(a).closest("*[data-dt-row]");return b.length?[b.data("dt-row")]:[]}if(typeof a==="string"&&a.charAt(0)==="#"){j=c.aIds[a.replace(/^#/,"")];if(j!==k)return[j.idx]}return h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},c,e)},1);c.selector.rows=a;c.selector.opts=b;return c});p("rows().nodes()",function(){return this.iterator("row",
|
||||
function(a,b){return a.aoData[b].nTr||k},1)});p("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ha(a.aoData,b,"_aData")},1)});s("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var d=b.aoData[c];return"search"===a?d._aFilterData:d._aSortData},1)});s("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",function(b,c){ca(b,c,a)})});s("rows().indexes()","row().index()",function(){return this.iterator("row",
|
||||
function(a,b){return b},1)});s("rows().ids()","row().id()",function(a){for(var b=[],c=this.context,d=0,e=c.length;d<e;d++)for(var f=0,g=this[d].length;f<g;f++){var h=c[d].rowIdFn(c[d].aoData[this[d][f]]._aData);b.push((!0===a?"#":"")+h)}return new r(c,b)});s("rows().remove()","row().remove()",function(){var a=this;this.iterator("row",function(b,c,d){var e=b.aoData,f=e[c],g,h,i,n,l;e.splice(c,1);g=0;for(h=e.length;g<h;g++)if(i=e[g],l=i.anCells,null!==i.nTr&&(i.nTr._DT_RowIndex=g),null!==l){i=0;for(n=
|
||||
l.length;i<n;i++)l[i]._DT_CellIndex.row=g}oa(b.aiDisplayMaster,c);oa(b.aiDisplay,c);oa(a[d],c,!1);Sa(b);c=b.rowIdFn(f._aData);c!==k&&delete b.aIds[c]});this.iterator("table",function(a){for(var c=0,d=a.aoData.length;c<d;c++)a.aoData[c].idx=c});return this});p("rows.add()",function(a){var b=this.iterator("table",function(b){var c,f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ma(b,c)[0]):h.push(N(b,c));return h},1),c=this.rows(-1);c.pop();h.merge(c,b);
|
||||
return c});p("row()",function(a,b){return bb(this.rows(a,b))});p("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});p("row().node()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]].nTr||null:null});p("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?
|
||||
ma(b,a)[0]:N(b,a)});return this.row(b[0])});var cb=function(a,b){var c=a.context;if(c.length&&(c=c[0].aoData[b!==k?b:a[0]])&&c._details)c._details.remove(),c._detailsShow=k,c._details=k},Vb=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];if(d._details){(d._detailsShow=b)?d._details.insertAfter(d.nTr):d._details.detach();var e=c[0],f=new r(e),g=e.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<G(g,"_details").length&&(f.on("draw.dt.DT_details",
|
||||
function(a,b){e===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(e===b)for(var c,d=aa(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",d)}),f.on("destroy.dt.DT_details",function(a,b){if(e===b)for(var c=0,d=g.length;c<d;c++)g[c]._details&&cb(f,c)}))}}};p("row().child()",function(a,b){var c=this.context;if(a===k)return c.length&&this.length?
|
||||
c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)cb(this);else if(c.length&&this.length){var d=c[0],c=c[0].aoData[this[0]],e=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?e.push(a):(c=h("<tr><td/></tr>").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=aa(d),e.push(c[0]))};f(a,b);c._details&&c._details.remove();c._details=h(e);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});
|
||||
p(["row().child.show()","row().child().show()"],function(){Vb(this,!0);return this});p(["row().child.hide()","row().child().hide()"],function(){Vb(this,!1);return this});p(["row().child.remove()","row().child().remove()"],function(){cb(this);return this});p("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var ec=/^(.+):(name|visIdx|visible)$/,Wb=function(a,b,c,d,e){for(var c=[],d=0,f=e.length;d<f;d++)c.push(B(a,e[d],b));
|
||||
return c};p("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var e=a,f=b,g=c.aoColumns,j=G(g,"sName"),i=G(g,"nTh");return $a("column",e,function(a){var b=Pb(a);if(a==="")return W(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var e=Ba(c,f);return h.map(g,function(b,f){return a(f,Wb(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(ec):"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],
|
||||
10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[Z(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});s("columns().header()",
|
||||
"column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});s("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});s("columns().data()","column().data()",function(){return this.iterator("column-rows",Wb,1)});s("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});s("columns().cache()","column().cache()",
|
||||
function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ha(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});s("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ha(a.aoData,e,"anCells",b)},1)});s("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m=
|
||||
h.inArray(!0,G(f,"bVisible"),c+1);i=0;for(n=j.length;i<n;i++)l=j[i].nTr,f=j[i].anCells,l&&l.insertBefore(f[c],f[m]||null)}else h(G(b.aoData,"anCells",c)).detach();g.bVisible=a;ea(b,b.aoHeader);ea(b,b.aoFooter);wa(b)}});a!==k&&(this.iterator("column",function(c,e){u(c,null,"column-visibility",[c,e,a,b])}),(b===k||b)&&this.columns.adjust());return c});s("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});p("columns.adjust()",
|
||||
function(){return this.iterator("table",function(a){Y(a)},1)});p("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return Z(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});p("column()",function(a,b){return bb(this.columns(a,b))});p("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",function(b){var d=a,e=ab(c),f=
|
||||
b.aoData,g=Ba(b,e),j=Sb(ha(f,g,"anCells")),i=h([].concat.apply([],j)),l,n=b.aoColumns.length,m,p,r,u,v,s;return $a("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){m=[];p=0;for(r=g.length;p<r;p++){l=g[p];for(u=0;u<n;u++){v={row:l,column:u};if(c){s=f[l];a(v,B(b,l,u),s.anCells?s.anCells[u]:null)&&m.push(v)}else m.push(v)}}return m}if(h.isPlainObject(a))return[a];c=i.filter(a).map(function(a,b){return{row:b._DT_CellIndex.row,column:b._DT_CellIndex.column}}).toArray();if(c.length||
|
||||
!a.nodeName)return c;s=h(a).closest("*[data-dt-row]");return s.length?[{row:s.data("dt-row"),column:s.data("dt-column")}]:[]},b,e)});var d=this.columns(b,c),e=this.rows(a,c),f,g,j,i,n,l=this.iterator("table",function(a,b){f=[];g=0;for(j=e[b].length;g<j;g++){i=0;for(n=d[b].length;i<n;i++)f.push({row:e[b][g],column:d[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});s("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b])&&
|
||||
a.anCells?a.anCells[c]:k},1)});p("cells().data()",function(){return this.iterator("cell",function(a,b,c){return B(a,b,c)},1)});s("cells().cache()","cell().cache()",function(a){a="search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,d){return b.aoData[c][a][d]},1)});s("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,d){return B(b,c,d,a)},1)});s("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,
|
||||
b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});s("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,d){ca(b,c,a,d)})});p("cell()",function(a,b,c){return bb(this.cells(a,b,c))});p("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?B(b[0],c[0].row,c[0].column):k;jb(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});p("order()",function(a,b){var c=this.context;if(a===k)return 0!==
|
||||
c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:a.length&&!h.isArray(a[0])&&(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});p("order.listener()",function(a,b,c){return this.iterator("table",function(d){Ma(d,a,b,c)})});p("order.fixed()",function(a){if(!a){var b=this.context,b=b.length?b[0].aaSortingFixed:k;return h.isArray(b)?{pre:b}:b}return this.iterator("table",function(b){b.aaSortingFixed=h.extend(!0,{},a)})});p(["columns().order()",
|
||||
"column().order()"],function(a){var b=this;return this.iterator("table",function(c,d){var e=[];h.each(b[d],function(b,c){e.push([c,a])});c.aaSorting=e})});p("search()",function(a,b,c,d){var e=this.context;return a===k?0!==e.length?e[0].oPreviousSearch.sSearch:k:this.iterator("table",function(e){e.oFeatures.bFilter&&fa(e,h.extend({},e.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),1)})});s("columns().search()","column().search()",function(a,
|
||||
b,c,d){return this.iterator("column",function(e,f){var g=e.aoPreSearchCols;if(a===k)return g[f].sSearch;e.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),fa(e,e.oPreviousSearch,1))})});p("state()",function(){return this.context.length?this.context[0].oSavedState:null});p("state.clear()",function(){return this.iterator("table",function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});p("state.loaded()",function(){return this.context.length?
|
||||
this.context[0].oLoadedState:null});p("state.save()",function(){return this.iterator("table",function(a){wa(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,d,e=0,f=a.length;e<f;e++)if(c=parseInt(b[e],10)||0,d=parseInt(a[e],10)||0,c!==d)return c>d;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?h("table",e.nScrollFoot)[0]:
|
||||
null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new r(c):c};m.camelToHungarian=K;p("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){p(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0].match(/\.dt\b/)||
|
||||
(a[0]+=".dt");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});p("clear()",function(){return this.iterator("table",function(a){na(a)})});p("settings()",function(){return new r(this.context,this.context)});p("init()",function(){var a=this.context;return a.length?a[0].oInit:null});p("data()",function(){return this.iterator("table",function(a){return G(a.aoData,"_aData")}).flatten()});p("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,
|
||||
d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),p;b.bDestroying=!0;u(b,"aoDestroyCallback","destroy",[b]);a||(new r(b)).columns().visible(!0);k.unbind(".DT").find(":not(tbody *)").unbind(".DT");h(D).unbind(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));b.aaSorting=[];b.aaSortingFixed=[];va(b);h(l).removeClass(b.asStripeClasses.join(" "));
|
||||
h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);b.bJUI&&(h("th span."+d.sSortIcon+", td span."+d.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+d.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%
|
||||
p])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column","row","cell"],function(a,b){p(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,n){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,n)})})});p("i18n()",function(a,b,c){var d=this.context[0],a=Q(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.12";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,
|
||||
sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,
|
||||
sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,
|
||||
fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===
|
||||
a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",
|
||||
sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",
|
||||
renderer:null,rowId:"DT_RowId"};X(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};X(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,
|
||||
bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],
|
||||
aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,
|
||||
fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=
|
||||
this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=v={buttons:{},classes:{},builder:"-source-",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},
|
||||
header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(v,{afnFiltering:v.search,aTypes:v.type.detect,ofnSearch:v.type.search,oSort:v.type.order,afnSortData:v.order,aoFeatures:v.feature,oApi:v.internal,oStdClasses:v.classes,oPagination:v.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",
|
||||
sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",
|
||||
sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Ca="",Ca="",H=Ca+"ui-state-default",ia=Ca+"css_right ui-icon ui-icon-",Xb=Ca+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses,
|
||||
m.ext.classes,{sPageButton:"fg-button ui-button "+H,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:H+" sorting_asc",sSortDesc:H+" sorting_desc",sSortable:H+" sorting",sSortableAsc:H+" sorting_asc_disabled",sSortableDesc:H+" sorting_desc_disabled",sSortableNone:H+" sorting_disabled",sSortJUIAsc:ia+"triangle-1-n",sSortJUIDesc:ia+"triangle-1-s",sSortJUI:ia+"carat-2-n-s",
|
||||
sSortJUIAscAllowed:ia+"carat-1-n",sSortJUIDescAllowed:ia+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+H,sScrollFoot:"dataTables_scrollFoot "+H,sHeaderTH:H,sFooterTH:H,sJUIHeader:Xb+" ui-corner-tl ui-corner-tr",sJUIFooter:Xb+" ui-corner-bl ui-corner-br"});var Mb=m.ext.pager;h.extend(Mb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ya(a,
|
||||
b)]},simple_numbers:function(a,b){return["previous",ya(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ya(a,b),"next","last"]},_numbers:ya,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},k,l,m=0,p=function(b,d){var o,r,u,s,v=function(b){Ta(a,b.data.action,true)};o=0;for(r=d.length;o<r;o++){s=d[o];if(h.isArray(s)){u=h("<"+(s.DT_el||"div")+"/>").appendTo(b);p(u,s)}else{k=null;
|
||||
l="";switch(s){case "ellipsis":b.append('<span class="ellipsis">…</span>');break;case "first":k=j.sFirst;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":k=j.sPrevious;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":k=j.sNext;l=s+(e<f-1?"":" "+g.sPageButtonDisabled);break;case "last":k=j.sLast;l=s+(e<f-1?"":" "+g.sPageButtonDisabled);break;default:k=s+1;l=e===s?g.sPageButtonActive:""}if(k!==null){u=h("<a>",{"class":g.sPageButton+" "+l,"aria-controls":a.sTableId,"aria-label":i[s],
|
||||
"data-dt-idx":m,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(k).appendTo(b);Wa(u,{action:s},v);m++}}}},r;try{r=h(b).find(I.activeElement).data("dt-idx")}catch(o){}p(h(b).empty(),d);r&&h(b).find("[data-dt-idx="+r+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&(!ac.test(a)||!bc.test(a)))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||M(a)?"date":
|
||||
null},function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Rb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Rb(a,c,!0)?"html-num-fmt"+c:null},function(a){return M(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return M(a)?a:"string"===typeof a?a.replace(Ob," ").replace(Aa,""):""},string:function(a){return M(a)?a:"string"===typeof a?a.replace(Ob,
|
||||
" "):a}});var za=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Qb(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(v.type.order,{"date-pre":function(a){return Date.parse(a)||0},"html-pre":function(a){return M(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return M(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<b?-1:a>b?1:0},"string-desc":function(a,
|
||||
b){return a<b?1:a>b?-1:0}});db("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("<div/>").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(e,
|
||||
f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Yb=function(a){return"string"===typeof a?a.replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):a};m.render={number:function(a,
|
||||
b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Yb(f);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Yb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Nb,_fnBuildAjax:ra,_fnAjaxUpdate:lb,_fnAjaxParameters:ub,_fnAjaxUpdateDraw:vb,_fnAjaxDataSrc:sa,_fnAddColumn:Ea,_fnColumnOptions:ja,
|
||||
_fnAdjustColumnSizing:Y,_fnVisibleToColumnIndex:Z,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:la,_fnColumnTypes:Ga,_fnApplyColumnDefs:ib,_fnHungarianMap:X,_fnCamelToHungarian:K,_fnLanguageCompat:Da,_fnBrowserDetect:gb,_fnAddData:N,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:jb,_fnSplitObjNotation:Ja,_fnGetObjectDataFn:Q,_fnSetObjectDataFn:R,
|
||||
_fnGetDataMaster:Ka,_fnClearTable:na,_fnDeleteIndex:oa,_fnInvalidate:ca,_fnGetRowElements:Ia,_fnCreateTr:Ha,_fnBuildHead:kb,_fnDrawHead:ea,_fnDraw:O,_fnReDraw:T,_fnAddOptionsHtml:nb,_fnDetectHeader:da,_fnGetUniqueThs:qa,_fnFeatureHtmlFilter:pb,_fnFilterComplete:fa,_fnFilterCustom:yb,_fnFilterColumn:xb,_fnFilter:wb,_fnFilterCreateSearch:Pa,_fnEscapeRegex:Qa,_fnFilterData:zb,_fnFeatureHtmlInfo:sb,_fnUpdateInfo:Cb,_fnInfoMacros:Db,_fnInitialise:ga,_fnInitComplete:ta,_fnLengthChange:Ra,_fnFeatureHtmlLength:ob,
|
||||
_fnFeatureHtmlPaginate:tb,_fnPageChange:Ta,_fnFeatureHtmlProcessing:qb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:rb,_fnScrollDraw:ka,_fnApplyToChildren:J,_fnCalculateColumnWidths:Fa,_fnThrottle:Oa,_fnConvertToWidth:Fb,_fnGetWidestNode:Gb,_fnGetMaxLenString:Hb,_fnStringToCss:x,_fnSortFlatten:V,_fnSort:mb,_fnSortAria:Jb,_fnSortListener:Va,_fnSortAttachListener:Ma,_fnSortingClasses:va,_fnSortData:Ib,_fnSaveState:wa,_fnLoadState:Kb,_fnSettingsFromNode:xa,_fnLog:L,_fnMap:E,_fnBindAction:Wa,_fnCallbackReg:z,
|
||||
_fnCallbackFire:u,_fnLengthOverflow:Sa,_fnRenderer:Na,_fnDataSource:y,_fnRowAttributes:La,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable});
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Input Mask plugin extensions
|
||||
http://github.com/RobinHerbots/jquery.inputmask
|
||||
Copyright (c) 2010 - 2014 Robin Herbots
|
||||
Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
|
||||
Version: 0.0.0
|
||||
|
||||
Optional extensions on the jquery.inputmask base
|
||||
*/
|
||||
(function ($) {
|
||||
//extra definitions
|
||||
$.extend($.inputmask.defaults.definitions, {
|
||||
'A': {
|
||||
validator: "[A-Za-z]",
|
||||
cardinality: 1,
|
||||
casing: "upper" //auto uppercasing
|
||||
},
|
||||
'#': {
|
||||
validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]",
|
||||
cardinality: 1,
|
||||
casing: "upper"
|
||||
}
|
||||
});
|
||||
$.extend($.inputmask.defaults.aliases, {
|
||||
'url': {
|
||||
mask: "ir",
|
||||
placeholder: "",
|
||||
separator: "",
|
||||
defaultPrefix: "http://",
|
||||
regex: {
|
||||
urlpre1: new RegExp("[fh]"),
|
||||
urlpre2: new RegExp("(ft|ht)"),
|
||||
urlpre3: new RegExp("(ftp|htt)"),
|
||||
urlpre4: new RegExp("(ftp:|http|ftps)"),
|
||||
urlpre5: new RegExp("(ftp:/|ftps:|http:|https)"),
|
||||
urlpre6: new RegExp("(ftp://|ftps:/|http:/|https:)"),
|
||||
urlpre7: new RegExp("(ftp://|ftps://|http://|https:/)"),
|
||||
urlpre8: new RegExp("(ftp://|ftps://|http://|https://)")
|
||||
},
|
||||
definitions: {
|
||||
'i': {
|
||||
validator: function (chrs, buffer, pos, strict, opts) {
|
||||
return true;
|
||||
},
|
||||
cardinality: 8,
|
||||
prevalidator: (function () {
|
||||
var result = [], prefixLimit = 8;
|
||||
for (var i = 0; i < prefixLimit; i++) {
|
||||
result[i] = (function () {
|
||||
var j = i;
|
||||
return {
|
||||
validator: function (chrs, buffer, pos, strict, opts) {
|
||||
if (opts.regex["urlpre" + (j + 1)]) {
|
||||
var tmp = chrs, k;
|
||||
if (((j + 1) - chrs.length) > 0) {
|
||||
tmp = buffer.join('').substring(0, ((j + 1) - chrs.length)) + "" + tmp;
|
||||
}
|
||||
var isValid = opts.regex["urlpre" + (j + 1)].test(tmp);
|
||||
if (!strict && !isValid) {
|
||||
pos = pos - j;
|
||||
for (k = 0; k < opts.defaultPrefix.length; k++) {
|
||||
buffer[pos] = opts.defaultPrefix[k]; pos++;
|
||||
}
|
||||
for (k = 0; k < tmp.length - 1; k++) {
|
||||
buffer[pos] = tmp[k]; pos++;
|
||||
}
|
||||
return { "pos": pos };
|
||||
}
|
||||
return isValid;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}, cardinality: j
|
||||
};
|
||||
})();
|
||||
}
|
||||
return result;
|
||||
})()
|
||||
},
|
||||
"r": {
|
||||
validator: ".",
|
||||
cardinality: 50
|
||||
}
|
||||
},
|
||||
insertMode: false,
|
||||
autoUnmask: false
|
||||
},
|
||||
"ip": { //ip-address mask
|
||||
mask: ["[[x]y]z.[[x]y]z.[[x]y]z.x[yz]", "[[x]y]z.[[x]y]z.[[x]y]z.[[x]y][z]"],
|
||||
definitions: {
|
||||
'x': {
|
||||
validator: "[012]",
|
||||
cardinality: 1,
|
||||
definitionSymbol: "i"
|
||||
},
|
||||
'y': {
|
||||
validator: function (chrs, buffer, pos, strict, opts) {
|
||||
if (pos - 1 > -1 && buffer[pos - 1] != ".")
|
||||
chrs = buffer[pos - 1] + chrs;
|
||||
else chrs = "0" + chrs;
|
||||
return new RegExp("2[0-5]|[01][0-9]").test(chrs);
|
||||
},
|
||||
cardinality: 1,
|
||||
definitionSymbol: "i"
|
||||
},
|
||||
'z': {
|
||||
validator: function (chrs, buffer, pos, strict, opts) {
|
||||
if (pos - 1 > -1 && buffer[pos - 1] != ".") {
|
||||
chrs = buffer[pos - 1] + chrs;
|
||||
if (pos - 2 > -1 && buffer[pos - 2] != ".") {
|
||||
chrs = buffer[pos - 2] + chrs;
|
||||
} else chrs = "0" + chrs;
|
||||
} else chrs = "00" + chrs;
|
||||
return new RegExp("25[0-5]|2[0-4][0-9]|[01][0-9][0-9]").test(chrs);
|
||||
},
|
||||
cardinality: 1,
|
||||
definitionSymbol: "i"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
+1627
File diff suppressed because it is too large
Load Diff
Vendored
+4
File diff suppressed because one or more lines are too long
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
|
||||
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
|
||||
* */
|
||||
|
||||
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);
|
||||
Reference in New Issue
Block a user