File: /home/teamadsc/public_html/wp-content/plugins/visitors/js/ahcpro_js_scripts.js
// Global number formatter — adds thousands separator (e.g. 125019 → "125,019")
function ahcProNumFormat(num) {
if (num === null || num === undefined || num === '') return num;
var n = Number(num);
if (isNaN(n)) return num;
return n.toLocaleString('en-US');
}
var colors = ['#DB6946', '#C14543', '#445060', '#395953', '#6C8C80', '#829AB5', '#BF807A', '#BF0000', '#006BB7', '#EC732C', '#BF3D27', '#A6375F',
'#8C6D46', '#326149', '#802B35', '#8A3842', '#366D73', '#4D6173', '#4A4659', '#C9D65B', '#F45552', '#F3CC5E', '#F29B88', '#D96941',
'#484F73', '#C9AB81', '#F5655C', '#F0C480'];
jQuery(document).ready(function () {
if (typeof google === 'object' && typeof google.maps === 'object') {
return;
} else {
}
});
//------------------------------------------------------------------------------
function convertToNumeric(data) {
if (data instanceof Array) {
for (var index in data) {
data[index] = Number(data[index]);
}
} else {
data = Number(data);
}
return data;
}
//------------------------------------------------------------------------------
function getRandomElementFromArray(array) {
var ranIndex = Math.floor(Math.random() * array.length);
return array[ranIndex];
}
//------------------------------------------------------------------------------
function drawVisitsLineChart(start_date, end_date, interval, visitors, visits, duration) {
// Safety check first
if (!visits || !visitors || visits.length === 0 || visitors.length === 0) {
jQuery('#visitscount').html('<div style="text-align:center;padding:50px;color:#666;">No chart data available</div>');
return;
}
// Prepare data for Chart.js
var labels = [];
var visitorsData = [];
var visitsData = [];
// Extract labels and data from the arrays
for (var i = 0; i < visits.length; i++) {
if (visits[i] && visits[i][0] && visits[i][1] !== undefined) {
// Format date for display
var date = new Date(visits[i][0]);
var formattedDate = (date.getMonth() + 1) + '/' + date.getDate();
labels.push(formattedDate);
visitsData.push(parseInt(visits[i][1]) || 0);
}
}
for (var i = 0; i < visitors.length; i++) {
if (visitors[i] && visitors[i][1] !== undefined) {
visitorsData.push(parseInt(visitors[i][1]) || 0);
}
}
var visitsColor = '#7c3aed'; // purple
var visitorsColor = '#f59e0b'; // amber
var barChartData = {
labels: labels,
datasets: [
{
label: "Visitors",
borderColor: visitorsColor,
backgroundColor: function(context) {
var chart = context.chart;
var ctx = chart.ctx;
var chartArea = chart.chartArea;
if (!chartArea) return null;
var grad = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);
grad.addColorStop(0, 'rgba(245, 158, 11, 0.18)');
grad.addColorStop(1, 'rgba(245, 158, 11, 0)');
return grad;
},
borderWidth: 2,
pointRadius: 4,
pointBackgroundColor: '#fff',
pointBorderColor: visitorsColor,
pointBorderWidth: 2,
pointHoverRadius: 6,
tension: 0.35,
fill: true,
data: visitorsData
},
{
label: "Visits",
borderColor: visitsColor,
backgroundColor: function(context) {
var chart = context.chart;
var ctx = chart.ctx;
var chartArea = chart.chartArea;
if (!chartArea) return null;
var grad = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);
grad.addColorStop(0, 'rgba(124, 58, 237, 0.18)');
grad.addColorStop(1, 'rgba(124, 58, 237, 0)');
return grad;
},
borderWidth: 2,
pointRadius: 4,
pointBackgroundColor: '#fff',
pointBorderColor: visitsColor,
pointBorderWidth: 2,
pointHoverRadius: 6,
tension: 0.35,
fill: true,
data: visitsData
}
]
};
// Clear previous chart
var ctx = document.getElementById("visitscount");
if (!ctx) {
return;
}
// Destroy existing chart if it exists
if (window.visitChart) {
window.visitChart.destroy();
}
// Create new chart
ctx = ctx.getContext("2d");
window.visitChart = new Chart(ctx, {
type: 'line',
data: barChartData,
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false
},
scales: {
y: {
beginAtZero: true,
border: { display: false },
grid: {
color: 'rgba(16, 24, 40, 0.05)',
drawTicks: false
},
ticks: {
stepSize: 1,
precision: 0,
color: '#98a2b3',
font: { size: 11 },
padding: 8
}
},
x: {
border: { display: false },
grid: { display: false },
ticks: {
color: '#98a2b3',
font: { size: 11 },
padding: 4
}
}
},
plugins: {
legend: {
display: true,
position: 'bottom',
align: 'start',
labels: {
boxWidth: 10,
boxHeight: 10,
usePointStyle: true,
pointStyle: 'circle',
color: '#475467',
font: { size: 12, weight: '500' },
padding: 16
}
},
tooltip: {
backgroundColor: '#101828',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: 'transparent',
padding: 10,
cornerRadius: 8,
displayColors: true,
boxPadding: 4,
titleFont: { size: 12, weight: '600' },
bodyFont: { size: 12 }
}
}
}
});
}
//------------------------------------------------------------------------------
function drawSrhEngVstLineChart() {
var srh_series = [];
var container = jQuery('#srchEngLegContainer');
var html = '';
document.getElementById('srchEngLegContainer').style.display = 'none';
// Search engine specific colors
const searchEngineColors = {
'google': '#4285f4',
'bing': '#00a650',
'yahoo': '#720e9e',
'duckduckgo': '#de5833',
'yandex': '#ffcc00',
'baidu': '#2932e1',
'unknown': '#95a5a6',
'other': '#34495e'
};
// Generate distinct colors based on item count
function generateDistinctColors(count) {
const colors = [];
const hueStep = 360 / count;
for (let i = 0; i < count; i++) {
const hue = i * hueStep;
const saturation = 70 + (i % 3) * 10;
const lightness = 45 + (i % 2) * 10;
colors.push(`hsl(${hue}, ${saturation}%, ${lightness}%)`);
}
return colors;
}
// Get all search engines with non-zero values first
var searchEngines = [];
for (var index in srhEngVisitsData.data.search_engines) {
var value = countVisits(srhEngVisitsData.data.search_engines[index]);
if (parseFloat(value) != 0) {
searchEngines.push({ name: index, value: value });
}
}
var ctx = document.getElementById("srhEngBieChartContainer").getContext("2d");
// Check if no data available
if (searchEngines.length === 0) {
// Clear any existing chart
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// Draw "No Data Available" message
ctx.font = "16px Arial";
ctx.fillStyle = "#666";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("No Data Available", ctx.canvas.width / 2, ctx.canvas.height / 2);
document.getElementById('srchEngLegContainer').style.display = 'none';
return;
}
// Generate distinct colors for unknown engines
var distinctColors = generateDistinctColors(searchEngines.length);
var unknownEngineIndex = 0;
document.getElementById('srchEngLegContainer').style.display = 'block';
searchEngines.forEach(function (engine, i) {
var color;
var engineKey = engine.name.toLowerCase().replace(/\s+/g, '').replace(/[^a-z]/g, '');
// Use predefined colors for known search engines
if (searchEngineColors[engineKey]) {
color = searchEngineColors[engineKey];
} else {
// Use generated colors for unknown engines
color = distinctColors[unknownEngineIndex];
unknownEngineIndex++;
}
srh_series.push({
"label": engine.name,
"value": engine.value,
"color": color
});
html += '<div class="legend">' +
'<span class="color" style="background-color: ' + color + ';"> </span>' +
'<span class="name">' + engine.name + '</span>' +
'<span class="value">' + ahcProNumFormat(engine.value) + '</span>' +
'</div>';
});
html += '<div class="cleaner"></div>';
container.html(html);
window.myPie = new Chart(ctx).Pie(srh_series, { responsive: true });
}
function drawBrowsersBieChart(browsersData) {
var brsBieChartData = [];
var container = jQuery('#browsersLegContainer');
var html = '';
// Browser specific colors
const browserColors = {
'chrome': '#4285f4',
'firefox': '#ff7139',
'safari': '#1c1c1e',
'edge': '#0078d4',
'opera': '#ff1b2d',
'internet explorer': '#1ebbee',
'unknown': '#95a5a6',
'other': '#34495e'
};
// Generate distinct colors based on item count
function generateDistinctColors(count) {
const colors = [];
const hueStep = 360 / count;
for (let i = 0; i < count; i++) {
const hue = i * hueStep;
const saturation = 70 + (i % 3) * 10;
const lightness = 45 + (i % 2) * 10;
colors.push(`hsl(${hue}, ${saturation}%, ${lightness}%)`);
}
return colors;
}
var ctx = document.getElementById("brsBiechartContainer").getContext("2d");
// Check if no data available
if (browsersData.length == 0) {
// Clear any existing chart
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// Draw "No Data Available" message
ctx.font = "16px Arial";
ctx.fillStyle = "#666";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("No Data Available", ctx.canvas.width / 2, ctx.canvas.height / 2);
document.getElementById('browsersLegContainer').style.display = 'none';
return;
}
document.getElementById('browsersLegContainer').style.display = 'block';
// Filter browsers with non-zero values
var validBrowsers = browsersData.filter(function (browser) {
return !isEmpty(Number(browser.hits));
});
var distinctColors = generateDistinctColors(validBrowsers.length);
for (var i = 0; i < browsersData.length; i++) {
var color;
var value = Number(browsersData[i].hits);
var browserKey = browsersData[i].bsr_name.toLowerCase().replace(/\s+/g, '');
// Use predefined colors for known browsers, otherwise use generated colors
if (browserColors[browserKey]) {
color = browserColors[browserKey];
} else {
color = distinctColors[i % distinctColors.length];
}
brsBieChartData[i] = { label: browsersData[i].bsr_name, value: value, color: color };
html += (isEmpty(value)) ? '' : '<div class="legend">' +
'<span class="color" style="background-color: ' + color + ';"> </span>' +
'<span class="name">' + browsersData[i].bsr_name + '</span>' +
'<span class="value">' + ahcProNumFormat(value) + '</span>' +
'</div>';
}
html += '<div class="cleaner"></div>';
container.html(html);
window.myPie = new Chart(ctx).Pie(brsBieChartData, { responsive: true });
}
function drawCountriesPieChart(countriesData) {
var countriesPieChartData = [];
var container = jQuery('#countriesLegContainer');
var html = '';
// Generate distinct colors based on item count
function generateDistinctColors(count) {
const colors = [];
const hueStep = 360 / count;
for (let i = 0; i < count; i++) {
const hue = i * hueStep;
const saturation = 70 + (i % 3) * 10;
const lightness = 45 + (i % 2) * 10;
colors.push(`hsl(${hue}, ${saturation}%, ${lightness}%)`);
}
return colors;
}
var ctx = document.getElementById("countriesPiechartContainer").getContext("2d");
// Check if no data available
if (countriesData.length == 0) {
// Clear any existing chart
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// Draw "No Data Available" message
ctx.font = "16px Arial";
ctx.fillStyle = "#666";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("No Data Available", ctx.canvas.width / 2, ctx.canvas.height / 2);
document.getElementById('countriesLegContainer').style.display = 'none';
return;
}
document.getElementById('countriesLegContainer').style.display = 'block';
// Filter countries with non-zero values
var validCountries = countriesData.filter(function (country) {
return !isEmpty(Number(country.visits));
});
var distinctColors = generateDistinctColors(validCountries.length);
for (var i = 0; i < countriesData.length; i++) {
var color = distinctColors[i % distinctColors.length];
var value = Number(countriesData[i].visits);
countriesPieChartData[i] = { label: countriesData[i].ctr_name, value: value, color: color };
html += (isEmpty(value)) ? '' : '<div class="legend">' +
'<span class="color" style="background-color: ' + color + ';"> </span>' +
'<span class="name">' + countriesData[i].ctr_name + '</span>' +
'<span class="value">' + ahcProNumFormat(value) + '</span>' +
'</div>';
}
html += '<div class="cleaner"></div>';
container.html(html);
window.myPie = new Chart(ctx).Pie(countriesPieChartData, { responsive: true });
}
function isEmpty(val) {
return (val == null || val == 0 || val == '' || val == '0');
}
//------------------------------------------------------------------------------
function countVisits(arr) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
count += Number(arr[i]);
}
return count;
}
//------------------------------------------------------------------------------
jQuery(document).ready(function () {
if (!jQuery('#countriesPiechartContainer').length) {
return;
}
//------------------------------------------
//if(visitsData.success && typeof visitsData.data != 'undefined'){
var duration = jQuery('#hits-duration').val();
drawVisitsLineChart(mystart_date, myend_date, '1 day', visitors_data, visits_data, duration);
//}
//------------------------------------------
if (browsersData.success && typeof browsersData.data != 'undefined' && typeof drawBrowsersBieChart === "function") {
drawBrowsersBieChart(browsersData.data);
}
//------------------------------------------
if (srhEngVisitsData.success && typeof srhEngVisitsData.data != 'undefined' && typeof drawSrhEngVstLineChart === "function") {
drawSrhEngVstLineChart(srhEngVisitsData);
}
//------------------------------------------
if (countriesData.success && typeof countriesData.data != 'undefined' && typeof drawCountriesPieChart === "function") {
drawCountriesPieChart(countriesData.data);
}
if (jQuery('#traffic_by_title').length) {
// Destroy existing instance if present
if (jQuery.fn.DataTable.isDataTable('#traffic_by_title')) {
jQuery('#traffic_by_title').DataTable().destroy();
}
var trafficTable = jQuery('#traffic_by_title').DataTable({
"pageLength": 10,
"searching": true,
"ordering": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
"bJQueryUI": true,
"processing": true,
"serverSide": true,
"deferRender": true,
"destroy": true,
ajax: {
url: ahc_ajax.ajax_url,
type: 'POST',
data: function(d) {
d.action = 'traffic_by_title';
return d;
},
dataSrc: 'data',
timeout: 60000,
error: function (xhr, error, thrown) {
console.error('Traffic by Title AJAX Error:', {
error: error,
thrown: thrown,
status: xhr.status,
responseText: xhr.responseText
});
if (error === 'timeout') {
alert('Request timed out. Please try filtering or search.');
}
}
},
columns: [
{
data: 'rank',
defaultContent: '-',
width: '5%'
},
{
data: 'til_page_title',
defaultContent: 'No title',
width: '50%' // Wider since we removed a column
},
{
data: 'til_hits',
defaultContent: '0',
width: '15%',
render: function (data, type, row) {
if (type === 'display') {
var cleanTitle = '';
if (row.til_page_title) {
cleanTitle = row.til_page_title.replace(/<[^>]*>/g, '').trim() || 'Unknown Page';
}
var postId = row.til_page_id || 0;
var hits = parseInt(data) || 0;
return '<div class="ahc-stats-cell">' +
'<a href="#" class="ahc-stats-number datatable-stats-link" ' +
'data-post-id="' + postId + '" ' +
'data-page-title="' + cleanTitle.replace(/"/g, '"') + '">' +
'<span class="dashicons dashicons-chart-bar"></span>' +
'<span class="stat-number">' + hits.toLocaleString() + ' hits</span>' +
'</a>' +
'</div>';
}
return data;
}
},
{
data: 'percent',
defaultContent: '0%',
width: '15%'
},
// TIME SPENT COLUMN REMOVED
{
data: 'bounce_rate',
defaultContent: '0%',
width: '15%'
}
],
language: {
searchPlaceholder: "Search by title...",
processing: "<div class='datatable-loading'><span class='loader'> </span><br>Loading...</div>",
zeroRecords: "No pages found.",
emptyTable: "No traffic data available yet.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
drawCallback: function (settings) {
if (settings._iDisplayLength > settings.fnRecordsDisplay()) {
jQuery(settings.nTableWrapper).find('.dataTables_paginate').hide();
} else {
jQuery(settings.nTableWrapper).find('.dataTables_paginate').show();
}
if (!jQuery(document).data('modal-events-bound')) {
if (typeof bindModalEvents === 'function') {
bindModalEvents();
jQuery(document).data('modal-events-bound', true);
}
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
text: '<i class="dashicons dashicons-media-spreadsheet"></i> Export',
title: "Traffic by Title",
className: 'btn-excel-export',
action: function (e, dt, node, config) {
jQuery("#traffic_by_title").parents(".panelcontent").find(".dataTables_processing").show();
setTimeout(function () {
jQuery.ajax({
url: ahc_ajax.ajax_url,
type: 'POST',
data: {
action: 'traffic_by_title',
page: 'all',
search: { value: dt.search() }
},
timeout: 120000,
success: function (res) {
try {
var xlsRows = (typeof res === 'string') ? JSON.parse(res) : res;
if (!Array.isArray(xlsRows)) throw new Error('Invalid data');
var createXLSLFormatObj = [];
// REMOVED "Time Spent" from header
var xlsHeader = ["Rank", "Page Title", "Hits", "Visit %", "Bounce Rate"];
createXLSLFormatObj.push(xlsHeader);
xlsRows.forEach(function (value) {
// REMOVED avg_time from export
createXLSLFormatObj.push([
value.rank || '-',
value.clean_title || value.til_page_title || 'No title',
value.til_hits || 0,
value.percent || '0%',
value.bounce_rate || '0%'
]);
});
var filename = "traffic_by_title_" + new Date().toISOString().slice(0,10) + ".xlsx";
var ws_name = "Traffic Data";
var wb = XLSX.utils.book_new();
var ws = XLSX.utils.aoa_to_sheet(createXLSLFormatObj);
// Adjusted column widths (removed time column)
ws['!cols'] = [
{wch: 8}, // Rank
{wch: 50}, // Title
{wch: 10}, // Hits
{wch: 10}, // Percent
{wch: 12} // Bounce Rate
];
XLSX.utils.book_append_sheet(wb, ws, ws_name);
XLSX.writeFile(wb, filename);
console.log('Excel export successful');
} catch (error) {
console.error('Excel error:', error);
alert('Error generating Excel: ' + error.message);
} finally {
jQuery("#traffic_by_title").parents(".panelcontent").find(".dataTables_processing").hide();
}
},
error: function (xhr, status, error) {
console.error('Export error:', {status, error, response: xhr.responseText});
alert('Export failed: ' + error);
jQuery("#traffic_by_title").parents(".panelcontent").find(".dataTables_processing").hide();
}
});
}, 100);
}
}]
});
console.log('Traffic by Title table initialized (without Time Spent)');
}
// Performance: Global variables with lazy initialization
window.ahcChart = null;
window.googleChartsLoaded = false;
window.googleChartsLoading = false;
window.modalCreated = false;
// Performance: Efficient event binding with delegation (only bind once)
function bindModalEvents() {
// Performance: Unbind existing events to prevent duplicates
jQuery(document).off('click.ahcModal', '.datatable-stats-link');
// Performance: Use namespaced events for better control
jQuery(document).on('click.ahcModal', '.datatable-stats-link', function (e) {
e.preventDefault();
var postId = jQuery(this).data('post-id');
var pageTitle = jQuery(this).data('page-title');
// Performance: Clean title efficiently
if (pageTitle.includes('http')) {
pageTitle = pageTitle.split('http')[0].trim();
}
pageTitle = pageTitle.replace(/[\/\s]*$/, '');
if (!pageTitle || pageTitle.length < 2) {
pageTitle = 'Page Statistics';
}
// Performance: Only create modal when first needed
if (!window.modalCreated) {
createStatsModal();
window.modalCreated = true;
}
// Performance: Lazy load Google Charts only when modal is opened
if (!window.googleChartsLoaded && !window.googleChartsLoading) {
loadGoogleCharts();
}
// Update modal and show
jQuery('#ahcModalTitle').text('Statistics: ' + pageTitle);
jQuery('#ahcModalLink').hide();
jQuery('#ahcHitsModal').data('post-id', postId);
jQuery('#ahcTimeRange').val('14');
// Performance: Show modal immediately, load data asynchronously
jQuery('#ahcHitsModal').show();
// Performance: Load chart data with debouncing
clearTimeout(window.chartLoadTimeout);
window.chartLoadTimeout = setTimeout(function () {
fetchChartData(postId, '14');
}, 100);
});
}
// Performance: Optimized chart destroyer
function destroyChart() {
if (window.ahcChart) {
try {
if (typeof window.ahcChart.clearChart === 'function') {
window.ahcChart.clearChart();
}
} catch (error) {
// Silent fail - don't log to avoid console spam
}
window.ahcChart = null;
}
}
// Performance: Create modal only when needed (lazy loading)
function createStatsModal() {
// Performance: Check if already created
if (jQuery('#ahcHitsModal').length) {
return;
}
var modalHtml = `
<div id="ahcHitsModal" class="ahc-modal">
<div class="ahc-modal-content">
<div class="ahc-modal-header">
<div class="ahc-modal-title-section">
<h2 id="ahcModalTitle">Page Statistics</h2>
<div id="ahcModalLink" class="ahc-modal-link"></div>
</div>
<span class="ahc-modal-close">×</span>
</div>
<div id="ahcStatsSummary" class="ahc-stats-summary"></div>
<div class="ahc-time-range">
<label for="ahcTimeRange"><strong>Time Range:</strong></label>
<select id="ahcTimeRange">
<option value="7">Last 7 days</option>
<option value="14" selected>Last 14 days</option>
<option value="30">Last 30 days</option>
<option value="this_month">This month</option>
</select>
</div>
<div class="ahc-chart-container">
<div id="ahcHitsChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>`;
jQuery('body').append(modalHtml);
// Performance: Only add CSS once
if (!jQuery('#ahc-modal-styles').length) {
addModalStyles();
}
// Performance: Bind events with efficient delegation
bindModalCloseEvents();
}
// Performance: Separate CSS loading to avoid re-adding
function addModalStyles() {
var styles = `
<style id="ahc-modal-styles">
.column-hits { width: 120px !important; text-align: center; }
.ahc-icon:before {
content: "\\f185";
color: #1DAE22;
font-family: dashicons;
position: relative;
top: 3px;
}
.ahc-stats-number {
display: flex;
flex-direction: column;
align-items: center;
text-decoration: none;
color: #2271b1;
gap: 2px;
padding: 4px;
border-radius: 3px;
transition: background-color 0.2s;
}
.ahc-stats-number:hover {
background-color: rgba(0,0,0,0.05);
}
.stat-number { font-size: 13px; font-weight: 500; }
.ahc-modal {
display: none;
position: fixed;
z-index: 999999;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.4);
}
.ahc-modal-content {
background-color: #fff;
margin: 5% auto;
padding: 20px;
border-radius: 4px;
width: 80%;
max-width: 800px;
max-height: 80vh;
overflow-y: auto;
}
.ahc-modal-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20px;
border-bottom: 2px solid #f0f0f0;
padding-bottom: 15px;
}
.ahc-modal-title-section {
flex: 1;
}
.ahc-modal-title-section h2 {
margin: 0 0 8px 0;
font-size: 22px;
font-weight: 600;
color: #2c3e50;
}
.ahc-modal-link {
font-size: 13px;
color: #7f8c8d;
font-family: monospace;
background: #f8f9fa;
padding: 4px 8px;
border-radius: 4px;
border: 1px solid #e9ecef;
word-break: break-all;
max-width: 500px;
}
.ahc-modal-close {
cursor: pointer;
font-size: 24px;
padding: 8px;
color: #7f8c8d;
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
background: #f8f9fa;
border: 1px solid #e9ecef;
}
.ahc-modal-close:hover {
background: #e74c3c;
color: white;
transform: scale(1.1);
}
.ahc-chart-container {
position: relative;
width: 100%;
margin-top: 20px;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
}
.ahc-time-range {
margin-bottom: 15px;
}
.ahc-stats-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
margin-bottom: 20px;
padding: 15px;
background: #f9f9f9;
border-radius: 4px;
}
.ahc-stat-item {
text-align: center;
}
.ahc-stat-number {
font-size: 24px;
font-weight: bold;
color: #1DAE22;
display: block;
}
.ahc-stat-label {
font-size: 12px;
color: #666;
text-transform: uppercase;
}
#traffic_by_title .ahc-stats-cell {
text-align: center;
}
</style>`;
jQuery('head').append(styles);
}
// Performance: Separate modal close event binding
function bindModalCloseEvents() {
// Performance: Use namespaced events and efficient delegation
jQuery(document).off('click.ahcModalClose').on('click.ahcModalClose', '.ahc-modal-close', function () {
jQuery('#ahcHitsModal').hide();
destroyChart();
});
jQuery(document).off('click.ahcModalOverlay').on('click.ahcModalOverlay', '#ahcHitsModal', function (e) {
if (e.target === this) {
jQuery('#ahcHitsModal').hide();
destroyChart();
}
});
// Performance: Debounced time range change
jQuery(document).off('change.ahcTimeRange').on('change.ahcTimeRange', '#ahcTimeRange', function () {
var postId = jQuery('#ahcHitsModal').data('post-id');
var range = jQuery(this).val();
clearTimeout(window.timeRangeTimeout);
window.timeRangeTimeout = setTimeout(function () {
fetchChartData(postId, range);
}, 200);
});
}
// Performance: Lazy load Google Charts only when needed
function loadGoogleCharts() {
if (window.googleChartsLoaded || window.googleChartsLoading) {
return;
}
window.googleChartsLoading = true;
// Performance: Check if already loaded
if (typeof google !== 'undefined' && google.charts) {
window.googleChartsLoaded = true;
window.googleChartsLoading = false;
return;
}
// Performance: Load from CDN with error handling
var script = document.createElement('script');
script.src = 'https://www.gstatic.com/charts/loader.js';
script.async = true;
script.onload = function () {
google.charts.load('current', {
'packages': ['corechart'],
'callback': function () {
window.googleChartsLoaded = true;
window.googleChartsLoading = false;
}
});
};
script.onerror = function () {
window.googleChartsLoading = false;
console.error('Failed to load Google Charts');
};
document.head.appendChild(script);
}
// Performance: Optimized chart data fetching with caching
var chartDataCache = {};
function fetchChartData(postId, range) {
// Performance: Cache key for avoiding duplicate requests
var cacheKey = postId + '_' + range;
var now = Date.now();
// Performance: Use cached data if less than 5 minutes old
if (chartDataCache[cacheKey] && (now - chartDataCache[cacheKey].timestamp) < 300000) {
var cachedData = chartDataCache[cacheKey].data;
updateSummaryStats(cachedData.summary);
createChart(cachedData.chart);
return;
}
// Performance: Abort previous request if still pending
if (window.currentChartRequest) {
window.currentChartRequest.abort();
}
window.currentChartRequest = jQuery.ajax({
url: ajaxurl || ahc_ajax.ajax_url,
method: "POST",
timeout: 15000,
data: {
action: "ahcpro_get_hits_data",
post_id: postId,
range: range
},
beforeSend: function () {
jQuery("#ahcHitsChart").html("<div style='text-align:center;padding:50px;color:#666;'>Loading chart...</div>");
},
success: function (response) {
window.currentChartRequest = null;
if (!response.success) {
jQuery("#ahcHitsChart").html("<div style='text-align:center;padding:50px;color:red;'>Error loading data</div>");
return;
}
var data = response.data;
// Performance: Cache the response
chartDataCache[cacheKey] = {
data: data,
timestamp: now
};
// Performance: Clean old cache entries (keep last 10)
var cacheKeys = Object.keys(chartDataCache);
if (cacheKeys.length > 10) {
var oldestKey = cacheKeys.reduce(function (oldest, key) {
return chartDataCache[key].timestamp < chartDataCache[oldest].timestamp ? key : oldest;
});
delete chartDataCache[oldestKey];
}
updateSummaryStats(data.summary);
// Performance: Create chart when Google Charts is ready
if (window.googleChartsLoaded) {
createChart(data.chart);
} else {
var checkInterval = setInterval(function () {
if (window.googleChartsLoaded) {
clearInterval(checkInterval);
createChart(data.chart);
}
}, 100);
setTimeout(function () {
clearInterval(checkInterval);
if (!window.googleChartsLoaded) {
jQuery("#ahcHitsChart").html("<div style='text-align:center;padding:50px;color:red;'>Chart library failed to load</div>");
}
}, 10000);
}
},
error: function (xhr, status, error) {
window.currentChartRequest = null;
if (status !== 'abort') {
jQuery("#ahcHitsChart").html("<div style='text-align:center;padding:50px;color:red;'>Failed to load data</div>");
}
}
});
}
// Performance: Optimized chart creation
function createChart(chartData) {
if (!chartData || !Array.isArray(chartData) || chartData.length === 0) {
jQuery("#ahcHitsChart").html("<div style='text-align:center;padding:50px;color:orange;'>No data available for chart</div>");
return;
}
destroyChart();
try {
// Performance: Pre-allocate array size
var dataArray = new Array(chartData.length + 1);
dataArray[0] = ['Date', 'Hits', 'Visitors'];
// Performance: Use for loop instead of forEach for better performance
for (var i = 0; i < chartData.length; i++) {
var item = chartData[i];
var date = item.date || 'Unknown';
var hits = parseInt(item.hits) || 0;
var visitors = parseInt(item.visitors) || 0;
var dateObj = new Date(date);
var formattedDate = dateObj.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric'
});
dataArray[i + 1] = [formattedDate, hits, visitors];
}
var data = google.visualization.arrayToDataTable(dataArray);
var options = {
title: 'Page Traffic Over Time',
titleTextStyle: {
fontSize: 16,
bold: true,
color: '#333'
},
hAxis: {
title: 'Date',
titleTextStyle: {
fontSize: 12,
bold: true
},
textStyle: {
fontSize: 11
}
},
vAxis: {
title: 'Count',
titleTextStyle: {
fontSize: 12,
bold: true
},
minValue: 0,
format: 'short',
viewWindow: {
min: 0
},
format: '#',
gridlines: {
count: -1
}
},
legend: {
position: 'top',
alignment: 'center',
textStyle: {
fontSize: 12
}
},
colors: ['#1DAE22', '#0073aa'],
lineWidth: 3,
pointSize: 6,
pointShape: 'circle',
backgroundColor: '#fff',
chartArea: {
left: 80,
top: 80,
width: '80%',
height: '65%'
},
animation: {
startup: true,
duration: 1000,
easing: 'out'
},
curveType: 'function',
explorer: {
actions: ['dragToZoom', 'rightClickToReset'],
axis: 'horizontal',
keepInBounds: true
},
series: {
0: {
color: '#1DAE22',
lineWidth: 3,
pointSize: 6
},
1: {
color: '#0073aa',
lineWidth: 3,
pointSize: 6
}
}
};
var chartDiv = document.getElementById('ahcHitsChart');
window.ahcChart = new google.visualization.LineChart(chartDiv);
window.ahcChart.draw(data, options);
} catch (error) {
jQuery("#ahcHitsChart").html("<div style='text-align:center;padding:50px;color:red;'>Error creating chart: " + error.message + "</div>");
}
}
// Performance: Optimized summary stats update
function updateSummaryStats(summary) {
var html = `
<div class="ahc-stat-item">
<span class="ahc-stat-number">${summary.total_hits.toLocaleString()}</span>
<span class="ahc-stat-label">Total Hits</span>
</div>
<div class="ahc-stat-item">
<span class="ahc-stat-number">${summary.unique_visitors.toLocaleString()}</span>
<span class="ahc-stat-label">Unique Visitors</span>
</div>
<div class="ahc-stat-item">
<span class="ahc-stat-number">${summary.avg_daily_hits.toLocaleString()}</span>
<span class="ahc-stat-label">Avg Daily Hits</span>
</div>
<div class="ahc-stat-item">
<span class="ahc-stat-number">${summary.peak_day_hits.toLocaleString()}</span>
<span class="ahc-stat-label">Peak Day</span>
</div>
`;
jQuery("#ahcStatsSummary").html(html);
}
// Performance: Initialize only essential components immediately
jQuery(document).ready(function ($) {
// Performance: Only bind initial events, create modal and load charts on demand
bindModalEvents();
// Performance: Clean up on page unload
jQuery(window).on('beforeunload', function () {
// Cancel any pending requests
if (window.currentChartRequest) {
window.currentChartRequest.abort();
}
// Clear timeouts
clearTimeout(window.chartLoadTimeout);
clearTimeout(window.timeRangeTimeout);
// Clear cache
chartDataCache = {};
});
});
if (jQuery('#lasest_search_words').length) {
latestSearchTable();
}
// Initialize table when ready
if (jQuery('#traffic_sources_table').length && jQuery('#traffic_sources_table tbody tr').length > 0) {
jQuery('#traffic_sources_table').DataTable({
"pageLength": 10,
"searching": false,
"ordering": true,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bJQueryUI": true,
"order": [[0, "asc"]],
language: {
"zeroRecords": "No traffic sources data available.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
columnDefs: [
{
targets: [1, 3],
orderable: false
}
],
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "Traffic Sources Report",
filename: "Traffic_Sources_Report",
exportOptions: {
columns: [0, 1, 2, 3],
format: {
body: function (data, row, col, node) {
// Strip HTML tags and clean text
const tempDiv = document.createElement("div");
tempDiv.innerHTML = data;
let cleanText = tempDiv.textContent || tempDiv.innerText || "";
// Clean up whitespace
cleanText = cleanText.replace(/\s+/g, ' ').trim();
return cleanText;
}
}
}
}]
});
}
function latestSearchTable() {
jQuery('#lasest_search_words_wrapper').html(`
<div class="panel" style="border-radius: 7px !important; border: 0 !important; box-shadow: 0 4px 25px 0 rgb(168 180 208 / 10%) !important;">
<h2 class="box-heading" style="border-radius: 7px 7px 0 0 !important; padding:12px 15px !important; border-bottom:0 !important">
Latest Search Words<span class="search_data"><a href="#" class="dashicons dashicons-search" title="Search"></a></span><span class="export_data">
<a href="#" class="dashicons dashicons-media-spreadsheet" title="Export to Excel"></a>
</span>
</h2>
<div class="panelcontent" style="border-radius:0 0 7px 7px !important; padding-right: 50px; text-align: center; padding: 40px 20px;">
<span class="spinner is-active" style="float: none; margin: 0 10px 0 0;"></span>
Checking Search Console connection...
</div>
</div>
`);
jQuery.ajax({
url: ahc_ajax.ajax_url,
method: 'POST',
data: {
action: 'test_gsc_connection_table',
},
success: function (response) {
if (response.success) {
// ✅ Connected, initialize the table
initializeSearchTable();
} else {
// ❌ Not connected - show error with proper panel structure
var errorMessage = response.data && response.data.message ? response.data.message : 'Connection failed';
showErrorInPanel(errorMessage);
}
},
error: function () {
showErrorInPanel('Could not verify the connection to Google Search Console. Please try again or check your settings.');
}
});
}
function showErrorInPanel(message) {
jQuery('#lasest_search_words_wrapper').html(`
<div class="panel" style="border-radius: 7px !important; border: 0 !important; box-shadow: 0 4px 25px 0 rgb(168 180 208 / 10%) !important;">
<h2 class="box-heading" style="border-radius: 7px 7px 0 0 !important; padding:12px 15px !important; border-bottom:0 !important">
Latest Search Words<span class="search_data"><a href="#" class="dashicons dashicons-search" title="Search"></a></span><span class="export_data">
<a href="#" class="dashicons dashicons-media-spreadsheet" title="Export to Excel"></a>
</span>
</h2>
<div class="panelcontent" style="border-radius:0 0 7px 7px !important; padding-right: 50px;">
<div style="padding: 30px 20px; text-align: center; background: #fff; border-left: 4px solid #dc3545;">
<div style="font-size: 48px; margin-bottom: 15px; color: #dc3545;">⚠️</div>
<div style="font-size: 14px; font-weight: 400; color: #721c24; margin-bottom: 10px;">
${message}
</div>
</div>
</div>
</div>
`);
}
function latestSearchTable() {
// Show loading state with proper panel structure
jQuery('#lasest_search_words_wrapper').html(`
<div class="panel" style="border-radius: 7px !important; border: 0 !important; box-shadow: 0 4px 25px 0 rgb(168 180 208 / 10%) !important;">
<h2 class="box-heading" style="border-radius: 7px 7px 0 0 !important; padding:12px 15px !important; border-bottom:0 !important">
Latest Search Words<span class="search_data"><a href="#" class="dashicons dashicons-search" title="Search"></a></span><span class="export_data">
<a href="#" class="dashicons dashicons-media-spreadsheet" title="Export to Excel"></a>
</span>
</h2>
<div class="panelcontent" style="border-radius:0 0 7px 7px !important; padding-right: 50px; text-align: center; padding: 40px 20px;">
<span class="spinner is-active" style="float: none; margin: 0 10px 0 0;"></span>
Checking Search Console connection...
</div>
</div>
`);
jQuery.ajax({
url: ahc_ajax.ajax_url,
method: 'POST',
data: {
action: 'test_gsc_connection_table',
},
success: function (response) {
if (response.success) {
// ✅ Connected, initialize the table
initializeSearchTable();
} else {
// ❌ Not connected - show error with proper panel structure
var errorMessage = response.data && response.data.message ? response.data.message : 'Connection failed';
showErrorInPanel(errorMessage);
}
},
error: function () {
showErrorInPanel('Could not verify the connection to Google Search Console. Please try again or check your settings.');
}
});
}
function initializeSearchTable() {
jQuery('#lasest_search_words_wrapper').html(`
<div class="panel" style="border-radius: 7px !important; border: 0 !important; box-shadow: 0 4px 25px 0 rgb(168 180 208 / 10%) !important;">
<h2 class="box-heading" style="border-radius: 7px 7px 0 0 !important; padding:12px 15px !important; border-bottom:0 !important">
Latest Search Words<span class="search_data"><a href="#" class="dashicons dashicons-search" title="Search"></a></span><span class="export_data">
<a href="#" class="dashicons dashicons-media-spreadsheet" title="Export to Excel"></a>
</span>
</h2>
<div class="search-panel ${jQuery('#from_dt').val() || jQuery('#to_dt').val() ? 'open' : ''}">
<form method="post" class="search_frm">
<label>Search in Time Frame: </label>
<input type="hidden" name="page" value="ahc_hits_counter_menu_pro" />
<input type="hidden" name="section" value="lastest_search" />
<input type="text" readonly="readonly" placeholder="From Date" class="ahc_clear" name="from_dt" id="from_dt" autocomplete="off" value="${jQuery('#from_dt').val() || ''}" />
<input type="text" readonly="readonly" placeholder="To Date" class="ahc_clear" name="to_dt" id="to_dt" autocomplete="off" value="${jQuery('#to_dt').val() || ''}" />
<input type="submit" class="button button-primary" />
<input type="button" class="button button-primary clear_form" value="Clear" />
</form>
</div>
<div class="panelcontent" style="border-radius:0 0 7px 7px !important; padding-right: 50px;">
<table width="100%" border="0" cellspacing="0" id="lasest_search_words">
<thead>
<tr>
<th width="25%">Country/SE/Browser</th>
<th width="65%">Country/SE/Browser</th>
<th width="65%">Keyword</th>
<th width="10%" class='text-center'>Date</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
`);
// Add click handler for search toggle
jQuery('#lasest_search_words_wrapper .search_data a').click(function (e) {
e.preventDefault();
jQuery('.search-panel').toggleClass('open');
});
// Initialize DataTable exactly like your traffic sources table
jQuery('#lasest_search_words').DataTable({
"pageLength": 10,
"searching": false,
"ordering": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bJQueryUI": true,
"processing": true,
"serverSide": true,
ajax: {
url: ahc_ajax.ajax_url + '?action=latest_search_words&fdt=' + jQuery("#from_dt").val() + "&tdt=" + jQuery("#to_dt").val(),
dataSrc: function (json) {
// Handle error response format
if (json.error && !json.success) {
setTimeout(function () {
showErrorInPanel(json.message);
}, 100);
return [];
}
return json.data || [];
},
error: function (xhr, error, code) {
setTimeout(function () {
showErrorInPanel('There was an error loading the search console data. Please try refreshing the page or check your connection settings.');
}, 100);
}
},
columnDefs: [{
targets: 1,
className: 'hide'
}],
columns: [
{ data: 'img' },
{ data: 'csb' },
{ data: 'keyword' },
{ data: 'dt' },
],
language: {
"zeroRecords": "No search data available yet. This is normal for new sites - Google needs 1-3 days to collect search data.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "Latest Search Words Report",
filename: "Latest_Search_Words_Report",
exportOptions: {
columns: [1, 2, 3],
format: {
body: function (data, row, col, node) {
// Strip HTML tags and clean text
const tempDiv = document.createElement("div");
tempDiv.innerHTML = data;
let cleanText = tempDiv.textContent || tempDiv.innerText || "";
// Clean up whitespace
cleanText = cleanText.replace(/\s+/g, ' ').trim();
return cleanText;
}
}
}
}]
});
jQuery('#lasest_search_words_wrapper .export_data a').click(function (e) {
e.preventDefault();
// Find the specific export button for THIS table only
jQuery('#lasest_search_words').closest('.dataTables_wrapper').find('.dt-buttons .buttons-excel').click();
});
}
if (jQuery('#traffic_by_countries').length) {
jQuery('#traffic_by_countries').DataTable({
"pageLength": 10,
"searching": false,
"ordering": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
"bJQueryUI": true,
"processing": true,
"serverSide": true,
ajax: ahc_ajax.ajax_url + '?action=traffic_by_countries',
dataSrc: 'data',
columns: [
{ data: 'rank' },
{ data: 'flag' },
{ data: 'ctr_name' },
{ data: 'visitors', render: function(d) { return ahcProNumFormat(d); } },
{ data: 'visits', render: function(d) { return ahcProNumFormat(d); } }
],
language: {
processing: "<span class='loader'> </span>",
"zeroRecords": "No data available.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "",
action: function (e, dt, node, config) {
jQuery("#traffic_by_countries").parents(".panelcontent").find(".dataTables_processing").show();
jQuery.ajax({
url: ahc_ajax.ajax_url + '?action=traffic_by_countries&page=all',
data: dt.ajax.params(),
success: function (res, status, xhr) {
//console.log(res);
var createXLSLFormatObj = [];
/* XLS Head Columns */
var xlsHeader = ["Rank", "Country", "Visitors", "Visits"];
/* XLS Rows Data */
var xlsRows = JSON.parse(res);
createXLSLFormatObj.push(xlsHeader);
jQuery.each(xlsRows, function (index, value) {
var innerRowData = [];
jQuery.each(value, function (ind, val) {
innerRowData.push(val);
});
createXLSLFormatObj.push(innerRowData);
});
jQuery("#traffic_by_countries").parents(".panelcontent").find(".dataTables_processing").hide();
/* File Name */
var filename = "traffic_by_countries.xlsx";
/* Sheet Name */
var ws_name = "sheet1";
if (typeof console !== 'undefined') console.log(new Date());
var wb = XLSX.utils.book_new(),
ws = XLSX.utils.aoa_to_sheet(createXLSLFormatObj);
/* Add worksheet to workbook */
XLSX.utils.book_append_sheet(wb, ws, ws_name);
/* Write workbook and Download */
if (typeof console !== 'undefined') console.log(new Date());
XLSX.writeFile(wb, filename);
if (typeof console !== 'undefined') console.log(new Date());
}
})
},
exportOptions: {
columns: [0, 2, 3, 4]
},
}]
});
}
if (jQuery('#top_refering_sites').find("tr").length > 1) {
jQuery('#top_refering_sites').DataTable({
"pageLength": 10,
"searching": false,
"ordering": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
language: {
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "Top Referring Sites", // This will be the sheet name
filename: "top_referring_sites" // This will be the file name
}]
});
}
if (jQuery('#recent_visit_by_ip').length) {
recentVisitorByIPTable();
}
if (jQuery('#visit_time_graph_table').length) {
visitTimeGraphTable();
}
function recentVisitorByIPTable() {
// Wait a bit for DOM to be fully ready
setTimeout(function() {
initializeTable();
}, 100);
}
function initializeTable() {
// Check if table element exists
if (jQuery('#recent_visit_by_ip').length === 0) {
return;
}
// Wait for DOM to be ready and find form elements
function getFormValues() {
// More comprehensive search for form elements
var year = '';
var month = '';
var ip = '';
// Find year element
var yearElement = null;
if (jQuery("#ahc_visitor_year").length) {
yearElement = jQuery("#ahc_visitor_year");
} else if (jQuery("#year").length) {
yearElement = jQuery("#year");
} else if (jQuery("select[name='year']").length) {
yearElement = jQuery("select[name='year']");
} else if (jQuery(".search_frm select").length) {
yearElement = jQuery(".search_frm select").first();
} else {
var allSelects = jQuery("select");
if (allSelects.length >= 1) {
yearElement = allSelects.eq(0);
}
}
// Find month element
var monthElement = null;
if (jQuery("#ahc_visitor_month").length) {
monthElement = jQuery("#ahc_visitor_month");
} else if (jQuery("#month").length) {
monthElement = jQuery("#month");
} else if (jQuery("select[name='month']").length) {
monthElement = jQuery("select[name='month']");
} else if (jQuery(".search_frm select").length >= 2) {
monthElement = jQuery(".search_frm select").eq(1);
} else {
var allSelects = jQuery("select");
if (allSelects.length >= 2) {
monthElement = allSelects.eq(1);
}
}
// Find IP element
var ipElement = null;
if (jQuery("#ahc_visitor_ip_addr").length) {
ipElement = jQuery("#ahc_visitor_ip_addr");
} else if (jQuery("#ip_addr").length) {
ipElement = jQuery("#ip_addr");
} else if (jQuery("input[name='ip_addr']").length) {
ipElement = jQuery("input[name='ip_addr']");
} else if (jQuery(".search_frm input[type='text']").length) {
ipElement = jQuery(".search_frm input[type='text']").first();
} else {
var allInputs = jQuery("input[type='text']");
if (allInputs.length >= 1) {
ipElement = allInputs.first();
}
}
// Get values with null checks
if (yearElement && yearElement.length) {
year = yearElement.val() || '';
}
if (monthElement && monthElement.length) {
month = monthElement.val() || '';
}
if (ipElement && ipElement.length) {
ip = ipElement.val() || '';
}
return { year: year, month: month, ip: ip };
}
// Initialize DataTable with proper search functionality
var table = jQuery('#recent_visit_by_ip').DataTable({
"pageLength": 10,
"searching": false,
"ordering": false,
"bLengthChange": false,
"bFilter": false,
"bInfo": false,
"bAutoWidth": false,
"bJQueryUI": true,
"processing": true,
"serverSide": true,
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
ajax: {
url: ahc_ajax.ajax_url + '?action=recent_visitor_by_ip',
type: 'GET',
data: function(d) {
var formValues = getFormValues();
// Add the form values
d.year = formValues.year;
d.month = formValues.month;
d.ip = formValues.ip;
return d;
},
dataSrc: 'data',
error: function(xhr, error, thrown) {
// Silent error handling
}
},
columns: [
{ data: 'hit_ip_address' },
{ data: 'ctr_name' },
{ data: 'time' },
{
data: 'duration',
defaultContent: '00:00:01'
},
{
data: 'day_hits',
render: function (data, type, row, meta) {
if (typeof data === 'string' && data.includes('<button')) {
var buttonHtml = data;
buttonHtml = buttonHtml.replace('<button', '<button ' +
'data-time="' + (row.time || '') + '" ' +
'data-ctr-name="' + (row.ctr_name || '') + '" ' +
'data-ctr-code="' + (row.ctr_internet_code || 'eg') + '" ' +
'data-city="' + (row.ahc_city || '') + '" ' +
'data-region="' + (row.ahc_region || '') + '"'
);
return buttonHtml;
}
return data;
}
}
],
language: {
processing: "<span class='loader'> </span>",
"zeroRecords": "No data available.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "",
action: function (e, dt, node, config) {
jQuery("#recent_visit_by_ip").parents(".panelcontent").find(".dataTables_processing").show();
// Get current search parameters using the robust function
var formValues = getFormValues();
// Make AJAX call for export with all data
jQuery.ajax({
url: ahc_ajax.ajax_url + '?action=recent_visitor_by_ip&page=all',
type: 'GET',
data: {
year: formValues.year,
month: formValues.month,
ip: formValues.ip
},
success: function (res) {
try {
var response = typeof res === 'string' ? JSON.parse(res) : res;
processExportData(response.data || []);
} catch (error) {
alert('Export failed. Please try again.');
jQuery("#recent_visit_by_ip").parents(".panelcontent").find(".dataTables_processing").hide();
}
},
error: function(xhr, status, error) {
alert('Export failed. Please try again.');
jQuery("#recent_visit_by_ip").parents(".panelcontent").find(".dataTables_processing").hide();
}
});
function processExportData(data) {
try {
var columnsToExport = ["hit_ip_address", "ctr_name", "time", "duration", "day_hits"];
var columnHeaders = ["IP Address", "Location", "Time", "Duration", "Day Hits"];
var values = data.map(function (item) {
return columnsToExport.map(function (column) {
if (column === 'day_hits') {
if (typeof item[column] === 'string' && item[column].includes('<button')) {
var match = item[column].match(/>(\d+)</);
return match ? match[1] : '0';
}
return item[column] || '0';
}
if (column === 'ctr_name') {
if (typeof item[column] === 'string') {
return item[column].replace(/<[^>]*>/g, '');
}
return item[column] || '';
}
if (column === 'duration') {
if (typeof item[column] === 'string' && item[column].includes(':')) {
return item[column];
}
if (typeof item[column] === 'number' || !isNaN(item[column])) {
var totalSeconds = parseInt(item[column]) || 0;
var hours = Math.floor(totalSeconds / 3600);
var minutes = Math.floor((totalSeconds % 3600) / 60);
var seconds = totalSeconds % 60;
return String(hours).padStart(2, '0') + ':' +
String(minutes).padStart(2, '0') + ':' +
String(seconds).padStart(2, '0');
}
return item[column] || '00:00:01';
}
return item[column] || '';
});
});
var workbook = XLSX.utils.book_new();
var worksheet = XLSX.utils.aoa_to_sheet([columnHeaders].concat(values));
worksheet['!cols'] = [
{wch: 15}, // IP Address
{wch: 30}, // Location
{wch: 20}, // Time
{wch: 12}, // Duration
{wch: 10} // Day Hits
];
XLSX.utils.book_append_sheet(workbook, worksheet, 'Recent Visitors');
XLSX.writeFile(workbook, 'recent_visitors_by_ip.xlsx');
} catch (error) {
alert('Export failed. Please check console for details.');
} finally {
jQuery("#recent_visit_by_ip").parents(".panelcontent").find(".dataTables_processing").hide();
}
}
}
}]
});
// Function to reset form values
function resetFormValues() {
var currentYear = new Date().getFullYear();
var currentMonth = (new Date().getMonth() + 1).toString().padStart(2, '0');
// Try multiple selectors to find and reset form elements
var yearElements = jQuery("#ahc_visitor_year, #year, select[name='year'], .search_frm select").first();
var monthElements = jQuery("#ahc_visitor_month, #month, select[name='month'], .search_frm select").eq(1);
var ipElements = jQuery("#ahc_visitor_ip_addr, #ip_addr, input[name='ip_addr'], .search_frm input[type='text']").first();
if (yearElements.length) yearElements.val(currentYear);
if (monthElements.length) monthElements.val(currentMonth);
if (ipElements.length) ipElements.val('');
}
// Use event delegation for form submission - cast a wider net
jQuery(document).on('submit', '#ahc_visitor_search_form, .search_frm, form', function(e) {
// Only handle forms related to our table
if (jQuery(this).closest('.panel').find('#recent_visit_by_ip').length === 0) {
return; // Not our form, let it proceed normally
}
e.preventDefault();
var formValues = getFormValues();
// Reload the DataTable with new parameters
table.ajax.reload(null, false);
return false;
});
// Backup: Handle submit button click directly
jQuery(document).on('click', 'input[type="submit"], button[type="submit"]', function(e) {
// Only handle buttons in forms related to our table
if (jQuery(this).closest('.panel').find('#recent_visit_by_ip').length === 0) {
return; // Not our button, let it proceed normally
}
e.preventDefault();
var formValues = getFormValues();
// Reload the DataTable directly
table.ajax.reload(null, false);
return false;
});
// Handle clear button with multiple selectors
jQuery(document).on('click', '.ahc_visitor_clear_form, .clear_form, input[value="Clear"], button[value="Clear"]', function(e) {
// Only handle clear buttons related to our table
if (jQuery(this).closest('.panel').find('#recent_visit_by_ip').length === 0) {
return; // Not our button, let it proceed normally
}
e.preventDefault();
resetFormValues();
// Reload table with cleared filters
table.ajax.reload(null, false);
// Close the search panel
jQuery('.search-panel').removeClass('open');
});
// Handle search panel toggle - make it specific to this table's search icon
jQuery('#recent_visit_by_ip').closest('.panel').find('.search_data a').on('click', function(e) {
e.preventDefault();
var searchPanel = jQuery(this).closest('.panel').find('.search-panel');
searchPanel.toggleClass('open');
});
// Modal functionality (keeping your existing modal code)
var modalDataCache = {};
jQuery(document).on('click', '[data-target="#DayHitsModal"]', function (event) {
event.preventDefault();
var button = jQuery(this);
var modal = jQuery('#DayHitsModal');
var table = jQuery('#recent_visit_by_ip').DataTable();
var row = table.row(button.closest('tr'));
var rowData = row.data();
var ip = button.data('hitipaddress') || '';
var duration = rowData.duration || '00:00:00';
var time = button.data('time') || '';
var hitdate = button.data('hitdate') || '';
var hitcountry = button.data('hitcountry') || '';
var ctrCode = button.data('ctr-code') || 'eg';
var ctrName = button.data('ctr-name') || '';
var city = button.data('city') || '';
var region = button.data('region') || '';
var country = 'Unknown';
var cityName = 'Unknown';
var flag = ctrCode.toLowerCase() || 'eg';
if (hitcountry) {
var parts = hitcountry.split('-');
if (parts.length >= 2) {
country = parts[0].trim();
cityName = parts[1].trim();
}
} else if (ctrName) {
var cleanText = ctrName.replace(/<[^>]*>/g, '');
var locationParts = cleanText.split(',');
if (locationParts.length >= 2) {
country = locationParts[0].trim();
cityName = locationParts[1].trim();
}
}
if (cityName === 'Unknown' && city) {
cityName = city;
}
modal.modal('show');
modal.find('.modal-title').text('IP Tracking - ' + ip);
var loadingHtml = `
<div class="loading-container" style="text-align: center; padding: 40px;">
<div class="spinner" style="border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 50px; height: 50px; animation: spin 1s linear infinite; margin: 0 auto 20px;"></div>
<p>Loading visitor data...</p>
<style>
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</div>
`;
modal.find('.modal-body').html(loadingHtml);
var cacheKey = ip + '_' + hitdate;
if (modalDataCache[cacheKey]) {
displayModalContent(modalDataCache[cacheKey], ip, duration, cityName, country, flag);
return;
}
jQuery.ajax({
url: ahc_ajax.ajax_url + '?action=ahcpro_get_visitor_path&_cb=' + Date.now(),
type: 'post',
dataType: 'json',
data: {
hitipaddress: ip,
hitdate: hitdate
},
timeout: 15000,
success: function (response) {
modalDataCache[cacheKey] = response;
displayModalContent(response, ip, duration, cityName, country, flag);
},
error: function (xhr, status, error) {
var errorHtml = `
<div class="error-container" style="text-align: center; padding: 40px; color: #dc3545;">
<i class="dashicons dashicons-warning" style="font-size: 48px; margin-bottom: 20px;"></i>
<h4>Failed to load visitor data</h4>
<p>Error: ${error || 'Network timeout or server error'}</p>
<button class="btn btn-secondary retry-btn" style="margin-top: 10px;" onclick="jQuery(this).closest('.modal').modal('hide');">Close</button>
</div>
`;
modal.find('.modal-body').html(errorHtml);
}
});
});
function displayModalContent(response, ip, duration, city, country, flag) {
var modal = jQuery('#DayHitsModal');
var deviceHtml = '';
if (response.os && response.browser) {
deviceHtml = `<i class="dashicons dashicons-desktop"></i> ${response.os}, ${response.browser}`;
} else if (response.browser) {
deviceHtml = `<i class="dashicons dashicons-desktop"></i> ${response.browser}`;
} else {
deviceHtml = `<i class="dashicons dashicons-desktop"></i> Unknown Device`;
}
var timelineHtml = '';
if (response.pages && response.pages.length) {
response.pages.forEach(function (page, idx) {
var pageTitle = page.title || 'Untitled Page';
var pageUrl = page.url || '#';
var pageTime = page.time || '';
timelineHtml += `
<div class="timeline-item">
<div class="step-info">
<div class="step-number">${idx + 1}</div>
<span class="step-arrow">→</span>
<span class="visit-time">${pageTime}</span>
<a href="${pageUrl}" target="_blank" class="page-title">
${pageTitle}
<svg class="external-link-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15,3 21,3 21,9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</a>
</div>
<div class="page-url">${pageUrl}</div>
</div>`;
});
} else {
timelineHtml = '<div style="color:#888; text-align: center; padding: 20px;">No page visits found for this session.</div>';
}
var modalContent = `
<style>
.modal-dialog {
max-width: 900px !important;
width: 85vw !important;
margin: 30px auto !important;
transition: box-shadow 0.3s cubic-bezier(.4,2,.6,1), transform 0.3s cubic-bezier(.4,2,.6,1);
}
@media (max-width: 768px) {
.modal-dialog {
width: 95vw !important;
margin: 10px auto !important;
}
}
.modal-content {
border-radius: 12px !important;
box-shadow: 0 8px 32px rgba(40,60,120,0.18) !important;
}
.visitor-header-enhanced {
display: flex; gap: 10px; align-items: center; margin-bottom: 14px;
background: #f8fafc; border-radius: 10px; padding: 8px 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
font-family: 'Segoe UI', 'Arial', sans-serif; font-size: 0.97em;
transition: box-shadow 0.3s, background 0.3s;
}
.visitor-header-enhanced:hover {
background: #e0e7ef;
box-shadow: 0 4px 16px rgba(40,60,120,0.10);
}
.visitor-header-enhanced img.flag {
border-radius: 4px; box-shadow: 0 1px 4px rgba(0,0,0,0.10);
border: 1px solid #e2e8f0;
}
.visitor-header-enhanced .city-country {
font-weight: bold; font-size: 1em; color: #222;
}
.visitor-header-enhanced .ip {
color: #444; font-size: 0.95em; background: #f1f5f9;
border-radius: 4px; padding: 1px 5px; margin-left: 2px;
}
.visitor-header-enhanced .duration {
color: #2563eb; font-size: 0.95em; background: #e0e7ef;
border-radius: 4px; padding: 1px 7px; margin-left: 2px;
font-weight: 500; transition: background 0.3s, color 0.3s;
}
.visitor-header-enhanced .duration:hover {
background: #2563eb; color: #fff;
}
.visitor-header-enhanced .device {
background: #e0e7ef; color: #2563eb; border-radius: 16px;
padding: 2px 8px 2px 6px; font-size: 0.93em;
display: flex; align-items: center; gap: 3px; margin-left: 2px;
transition: background 0.3s, color 0.3s;
}
.visitor-header-enhanced .device:hover {
background: #2563eb; color: #fff;
}
.visit-timeline-enhanced {
font-family: 'Fira Mono', 'Consolas', 'monospace';
border-left: 3px solid #e0e7ef;
margin-left: 10px;
padding-left: 18px;
}
.visit-timeline-enhanced .timeline-item {
position: relative;
margin-bottom: 20px;
padding-left: 8px;
transition: background 0.2s;
border-radius: 6px;
padding-top: 8px;
padding-bottom: 8px;
}
.visit-timeline-enhanced .timeline-item:hover {
background: #f1f5fb;
}
.visit-timeline-enhanced .timeline-item:before {
content: '';
position: absolute;
left: -18px;
top: 12px;
width: 10px;
height: 10px;
background: #2563eb;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 0 0 2px #e0e7ef;
}
.visit-timeline-enhanced .step-info {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
flex-wrap: wrap;
}
.visit-timeline-enhanced .step-number {
background: #2563eb;
color: white;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
flex-shrink: 0;
}
.visit-timeline-enhanced .visit-time {
color: #2563eb;
font-weight: bold;
margin-right: 10px;
font-size: 0.9em;
}
.visit-timeline-enhanced .step-arrow {
color: #666;
font-size: 16px;
margin: 0 5px;
font-weight: bold;
}
.visit-timeline-enhanced .page-title {
color: #0073aa;
text-decoration: none;
font-weight: 500;
transition: color 0.2s;
flex: 1;
display: flex;
align-items: center;
gap: 6px;
}
.visit-timeline-enhanced .page-title:hover {
color: #2563eb;
text-decoration: underline;
}
.visit-timeline-enhanced .external-link-icon {
width: 12px;
height: 12px;
opacity: 0.6;
transition: opacity 0.2s;
flex-shrink: 0;
}
.visit-timeline-enhanced .page-title:hover .external-link-icon {
opacity: 1;
}
.visit-timeline-enhanced .page-url {
color: #888;
font-size: 11px;
margin-top: 4px;
word-break: break-all;
line-height: 1.4;
padding-left: 32px;
background: #f8f9fa;
padding: 4px 8px;
border-radius: 4px;
border-left: 3px solid #e0e7ef;
margin-left: 32px;
}
</style>
<div class="visitor-header-enhanced">
<img class="flag" src="https://flagcdn.com/w40/${flag}.png" alt="flag" width="32" height="24" onerror="this.src='https://flagcdn.com/w40/xx.png';" />
<div class="city-country">${city}, ${country}</div>
<div class="ip">IP: ${ip}</div>
<div class="duration">Duration: ${duration}</div>
<div class="device">${deviceHtml}</div>
</div>
<div class="visit-timeline-enhanced">${timelineHtml}</div>
`;
modal.find('.modal-body').html(modalContent);
}
jQuery('#DayHitsModal').on('hide.bs.modal', function (event) {
jQuery('.modal-body').html('');
});
setInterval(function () {
if (Object.keys(modalDataCache).length > 100) {
var keys = Object.keys(modalDataCache);
var keysToDelete = keys.slice(0, keys.length - 50);
keysToDelete.forEach(function (key) {
delete modalDataCache[key];
});
}
}, 300000);
}
function visitTimeGraphTable() {
// Get current hour to calculate the starting page
const currentHour = new Date().getHours();
const pageLength = 10;
const startingPage = Math.floor(currentHour / pageLength);
const table = jQuery('#visit_time_graph_table').DataTable({
"pageLength": pageLength,
"searching": false,
"ordering": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
"bJQueryUI": true,
"processing": true,
"serverSide": true,
"displayStart": startingPage * pageLength, // Start at the page containing current hour
ajax: {
url: ahc_ajax.ajax_url + '?action=visits_time_graph&fdt=' + jQuery("#vfrom_dt").val() + "&tdt=" + jQuery("#vto_dt").val(),
data: function (d) {
// Add current hour info to the request
d.current_hour = currentHour;
return d;
}
},
dataSrc: 'data',
columns: [
{ data: 'time' },
{ data: 'graph' },
{ data: 'vtm_visitors', render: function(d) { return ahcProNumFormat(d); } },
{ data: 'vtm_visits', render: function(d) { return ahcProNumFormat(d); } }
],
language: {
processing: "<span class='loader'> </span>",
"zeroRecords": "No data available.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
// Highlight current hour row after each draw
highlightCurrentHourRow();
},
"fnInitComplete": function (oSettings) {
// Scroll to current hour row after initial load
setTimeout(function () {
highlightCurrentHourRow();
}, 500);
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "",
action: function (e, dt, node, config) {
jQuery("#visit_time_graph_table").parents(".panelcontent").find(".dataTables_processing").show();
jQuery.ajax({
url: ahc_ajax.ajax_url + '?action=visits_time_graph&page=all&fdt=' + jQuery("#vfrom_dt").val() + "&tdt=" + jQuery("#vto_dt").val(),
data: dt.ajax.params(),
success: function (res, status, xhr) {
var createXLSLFormatObj = [];
var xlsHeader = ["Time", "Visitors", "Visits", "Graph"];
var xlsRows = JSON.parse(res);
createXLSLFormatObj.push(xlsHeader);
jQuery.each(xlsRows, function (index, value) {
var innerRowData = [];
jQuery.each(value, function (ind, val) {
innerRowData.push(val);
});
createXLSLFormatObj.push(innerRowData);
});
jQuery("#visit_time_graph_table").parents(".panelcontent").find(".dataTables_processing").hide();
var filename = "visits_time_graph.xlsx";
var ws_name = "sheet1";
if (typeof console !== 'undefined') console.log(new Date());
var wb = XLSX.utils.book_new(),
ws = XLSX.utils.aoa_to_sheet(createXLSLFormatObj);
XLSX.utils.book_append_sheet(wb, ws, ws_name);
if (typeof console !== 'undefined') console.log(new Date());
XLSX.writeFile(wb, filename);
if (typeof console !== 'undefined') console.log(new Date());
}
})
},
}]
});
return table;
}
// Function to highlight current hour row
function highlightCurrentHourRow() {
const currentHour = new Date().getHours();
const currentTimeString = (currentHour < 10 ? '0' + currentHour : currentHour) + ':00 - ' + (currentHour < 10 ? '0' + currentHour : currentHour) + ':59';
// Remove previous highlighting
jQuery('#visit_time_graph_table tbody tr').removeClass('current-hour-row');
// Find and highlight current hour row
jQuery('#visit_time_graph_table tbody tr').each(function () {
const timeCell = jQuery(this).find('td:first-child').text().trim();
if (timeCell === currentTimeString) {
jQuery(this).addClass('current-hour-row');
// Make the entire row text bold
jQuery(this).css('font-weight', 'bold');
}
});
}
// Update current time display every minute
function updateCurrentTimeDisplay() {
const now = new Date();
const timeString = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0');
// Update the time display in header if it exists
const timeDisplay = jQuery('.current-time-display');
if (timeDisplay.length) {
timeDisplay.text('Current Time: ' + timeString);
}
// Re-highlight current hour row in case hour changed
highlightCurrentHourRow();
}
// Set up auto-refresh for time display
setInterval(updateCurrentTimeDisplay, 60000); // Update every minute
if (jQuery('#today_traffic_index_by_country').length) {
trafficByIndexCountryTable();
}
function trafficByIndexCountryTable() {
jQuery('#today_traffic_index_by_country').DataTable({
"pageLength": 10,
"searching": false,
"ordering": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
"bJQueryUI": true,
"processing": true,
"serverSide": true,
ajax: ahc_ajax.ajax_url + '?action=today_traffic_index&fdt=' + jQuery("#t_from_dt").val() + "&tdt=" + jQuery("#t_to_dt").val(),
dataSrc: 'data',
columns: [
{ data: 'no' },
{ data: 'country' },
{ data: 'ctr_name' },
{ data: 'total', render: function(d) { return ahcProNumFormat(d); } },
],
language: {
processing: "<span class='loader'> </span>",
"zeroRecords": "No data available.",
paginate: {
next: '<i class="dashicons dashicons-arrow-right-alt2"></i>',
previous: '<i class="dashicons dashicons-arrow-left-alt2"></i>'
}
},
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "",
action: function (e, dt, node, config) {
jQuery("#today_traffic_index_by_country").parents(".panelcontent").find(".dataTables_processing").show();
jQuery.ajax({
url: ahc_ajax.ajax_url + '?action=today_traffic_index&page=all&fdt=' + jQuery("#t_from_dt").val() + "&tdt=" + jQuery("#t_to_dt").val(),
data: dt.ajax.params(),
success: function (res, status, xhr) {
//console.log(res);
var createXLSLFormatObj = [];
/* XLS Head Columns */
var xlsHeader = ["No", "Country", "Total"];
/* XLS Rows Data */
var xlsRows = JSON.parse(res);
createXLSLFormatObj.push(xlsHeader);
jQuery.each(xlsRows, function (index, value) {
var innerRowData = [];
jQuery.each(value, function (ind, val) {
innerRowData.push(val);
});
createXLSLFormatObj.push(innerRowData);
});
jQuery("#today_traffic_index_by_country").parents(".panelcontent").find(".dataTables_processing").hide();
/* File Name */
var filename = "today_traffic_index.xlsx";
/* Sheet Name */
var ws_name = "sheet1";
if (typeof console !== 'undefined') console.log(new Date());
var wb = XLSX.utils.book_new(),
ws = XLSX.utils.aoa_to_sheet(createXLSLFormatObj);
/* Add worksheet to workbook */
XLSX.utils.book_append_sheet(wb, ws, ws_name);
/* Write workbook and Download */
if (typeof console !== 'undefined') console.log(new Date());
XLSX.writeFile(wb, filename);
if (typeof console !== 'undefined') console.log(new Date());
}
})
},
exportOptions: {
columns: [0, 2, 3]
},
}]
});
}
if (jQuery('#summary_statistics').find("tr").length > 1) {
jQuery('#summary_statistics').DataTable({
"pageLength": 100,
"searching": false,
"ordering": false,
"bPaginate": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: "summary_statistics", // This will be the sheet name
filename: "summary_statistics" // This will be the file name
}]
});
}
if (jQuery('#search_engine').find("tr").length > 1) {
jQuery('#search_engine').DataTable({
"pageLength": 100,
"searching": false,
"ordering": false,
"bPaginate": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false,
"fnDrawCallback": function (oSettings) {
if (oSettings._iDisplayLength > oSettings.fnRecordsDisplay()) {
jQuery(oSettings.nTableWrapper).find('.dataTables_paginate').hide();
}
},
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
title: ""
}]
});
}
jQuery(".export_data a").click(function (e) {
e.preventDefault();
jQuery(this).parents(".panel").find(".dt-buttons").find(".dt-button").trigger("click");
})
var dateFormat = "mm-dd-yy";
if (jQuery("#from_dt").length && jQuery("#to_dt").length) {
var from = jQuery("#from_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
var to = jQuery("#to_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
}
if (jQuery("#summary_from_dt").length && jQuery("#summary_to_dt").length) {
var from = jQuery("#summary_from_dt").datepicker({
defaultDate: 0,
dateFormat: "yy-mm-dd",
numberOfMonths: 1
});
var to = jQuery("#summary_to_dt").datepicker({
defaultDate: 0,
dateFormat: "yy-mm-dd",
numberOfMonths: 1
});
}
jQuery("#to_dt").on("change", function () {
from.datepicker("option", "maxDate", getDate(this));
});
jQuery("#from_dt").on("change", function () {
to.datepicker("option", "minDate", getDate(this));
});
if (jQuery("#t_from_dt").length && jQuery("#t_to_dt").length) {
var t_from_dt = jQuery("#t_from_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
var t_to_dt = jQuery("#t_to_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
}
jQuery("#t_to_dt").on("change", function () {
t_from_dt.datepicker("option", "maxDate", getDate(this));
});
jQuery("#t_from_dt").on("change", function () {
t_to_dt.datepicker("option", "minDate", getDate(this));
});
if (jQuery("#vfrom_dt").length && jQuery("#vto_dt").length) {
var vfrom = jQuery("#vfrom_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
var vto = jQuery("#vto_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
}
jQuery("#vto_dt").on("change", function () {
vfrom.datepicker("option", "maxDate", getDate(this));
});
jQuery("#vfrom_dt").on("change", function () {
vto.datepicker("option", "minDate", getDate(this));
});
if (jQuery("#r_from_dt").length && jQuery("#r_to_dt").length) {
var vfrom = jQuery("#r_from_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
var vto = jQuery("#r_to_dt").datepicker({
defaultDate: 0,
dateFormat: "mm-dd-yy",
numberOfMonths: 1
});
}
jQuery("#r_to_dt").on("change", function () {
vfrom.datepicker("option", "maxDate", getDate(this));
});
jQuery("#r_from_dt").on("change", function () {
vto.datepicker("option", "minDate", getDate(this));
});
function getDate(element) {
var date;
try {
date = jQuery.datepicker.parseDate(dateFormat, element.value);
} catch (error) {
date = null;
}
return date;
}
jQuery(".search-panel .search_frm").submit(function (e) {
e.preventDefault();
var tableID = jQuery(this).parents(".panel").find(".panelcontent").find("table").attr("id");
if (tableID == "recent_visit_by_ip") {
jQuery('#' + tableID).DataTable().destroy();
recentVisitorByIPTable();
return false;
}
else if (tableID == "today_traffic_index_by_country") {
jQuery('#' + tableID).DataTable().destroy();
trafficByIndexCountryTable();
return false;
}
else if (tableID == "lasest_search_words") {
jQuery('#' + tableID).DataTable().destroy();
latestSearchTable();
return false;
}
else if (tableID == "visit_time_graph_table") {
jQuery('#' + tableID).DataTable().destroy();
visitTimeGraphTable();
return false;
}
else
return true;
});
jQuery(".clear_form").click(function (e) {
jQuery(this).parents("form").find(".ahc_clear").val("");
jQuery(this).parents("form").submit();
});
jQuery(".search_data a").click(function (e) {
e.preventDefault();
if (jQuery(this).parents(".panel").find(".search-panel").length)
jQuery(this).parents(".panel").find(".search-panel").slideToggle();
if (jQuery(this).parents(".panel").find(".dataTables_filter").length)
jQuery(this).parents(".panel").find(".dataTables_filter").slideToggle();
});
});