-
-
Notifications
You must be signed in to change notification settings - Fork 313
Chart Fixed #3998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chart Fixed #3998
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% load custom_tags %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% get_current_template as current_template %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% get_page_views current_template 30 as page_views %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% get_current_url_path as current_url_path %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% get_page_views current_url_path 30 as page_views %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% get_page_votes current_template as upvotes %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {% get_page_votes current_template "downvote" as downvotes %} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div id="pageStatsContainer" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -16,11 +17,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| </svg> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <!-- Stats Content --> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="bg-white shadow-lg rounded-lg p-3 w-64"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="text-sm font-medium text-gray-700 mb-2">Page Statistics (Last 30 Days)</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="bg-white shadow-lg rounded-lg p-3 w-72"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="text-sm font-medium text-gray-700 mb-2">Page Views (Last 30 Days)</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <!-- Bar Chart --> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="mb-3"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <canvas id="pageViewsChart" height="100"></canvas> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <canvas id="pageViewsChart" height="120"></canvas> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <!-- Vote Buttons --> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="flex justify-between items-center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -36,6 +37,9 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span id="upvoteCount" class="text-sm">{{ upvotes }}</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="text-xs text-center text-gray-500"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Total: <span id="totalViews">0</span> views | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="flex items-center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button id="downvoteBtn" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="text-gray-600 hover:text-[#e74c3c] focus:outline-none mr-2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -63,46 +67,102 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ctx = document.getElementById('pageViewsChart').getContext('2d'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Initialize default empty data structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let viewsByDate = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Safely parse the page views data from Django template | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Safely parse the page views data from Django template | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let pageViewsData; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Try to parse the data, ensuring it's an array of numbers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageViewsData = JSON.parse('{{ page_views|safe|escapejs }}'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(pageViewsData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensure the data consists of numbers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageViewsData = pageViewsData.map(count => Number(count) || 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('Failed to parse page views data:', e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageViewsData = Array(30).fill(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Generate labels for the last 30 days (day numbers only) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const labels = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const today = new Date(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 29; i >= 0; i--) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const date = new Date(today); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date.setDate(date.getDate() - i); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| labels.push(date.getDate()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get the raw JSON string and ensure it's properly escaped/formatted | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rawData = '{{ page_views|escapejs }}'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Parse the JSON data only if it's not empty | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (rawData && rawData.trim() !== '') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewsByDate = JSON.parse(rawData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('Successfully parsed view data:', viewsByDate); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn('Empty page views data received'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('Failed to parse page views data:', e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensure viewsByDate is an object, not null or undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!viewsByDate || typeof viewsByDate !== 'object') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn('Invalid view data structure, creating empty object'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewsByDate = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Sort the dates chronologically | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sortedDates = Object.keys(viewsByDate).sort(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Extract data in chronological order | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dateLabels = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pageViewsData = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Format dates for display | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const shortMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Process each date if we have any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (sortedDates.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const dateStr of sortedDates) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Parse the date from the YYYY-MM-DD format | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dateParts = dateStr.split('-'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (dateParts.length !== 3) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn(`Invalid date format: ${dateStr}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const year = parseInt(dateParts[0], 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const month = parseInt(dateParts[1], 10) - 1; // 0-based month | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const day = parseInt(dateParts[2], 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Validate date parts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isNaN(year) || isNaN(month) || isNaN(day) || month < 0 || month > 11 || day < 1 || day > 31) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn(`Invalid date parts: ${year}-${month+1}-${day}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Format for display | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dateLabels.push(`${shortMonthNames[month]} ${day}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add view count for this date (ensure it's a number) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const viewCount = parseInt(viewsByDate[dateStr], 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageViewsData.push(isNaN(viewCount) ? 0 : viewCount); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn(`Error processing date ${dateStr}:`, e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skip this date if there's an error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If no data, generate default empty data for the last 30 days | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const today = new Date(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 29; i >= 0; i--) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const date = new Date(today); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date.setDate(date.getDate() - i); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dateLabels.push(`${shortMonthNames[date.getMonth()]} ${date.getDate()}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageViewsData.push(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Calculate total views - ensure we're only summing numbers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const totalViews = pageViewsData.reduce((sum, count) => sum + (isNaN(count) ? 0 : count), 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| document.getElementById('totalViews').textContent = totalViews; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create the chart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new Chart(ctx, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: 'bar', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| labels: labels, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| labels: dateLabels, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| datasets: [{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label: 'Unique Views', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label: 'Views', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: pageViewsData, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| backgroundColor: 'rgba(231, 76, 60, 0.7)', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderColor: '#e74c3c', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderWidth: 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderRadius: 4, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| barPercentage: 0.7, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| categoryPercentage: 0.8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| barPercentage: 0.8, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| categoryPercentage: 0.9 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| options: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -116,12 +176,28 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callbacks: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: function(tooltipItems) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const date = new Date(today); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date.setDate(date.getDate() - (29 - tooltipItems[0].dataIndex)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return date.toLocaleDateString(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const index = tooltipItems[0].dataIndex; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (sortedDates.length > 0 && index < sortedDates.length) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dateStr = sortedDates[index]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const date = new Date(dateStr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isNaN(date.getTime())) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return date.toLocaleDateString('en-US', { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| weekday: 'long', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| year: 'numeric', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| month: 'long', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| day: 'numeric' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn('Error formatting tooltip date:', e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fallback to just showing the label if we can't format the date | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return dateLabels[index] || 'Unknown Date'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label: function(context) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const count = context.raw || 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const count = isNaN(context.raw) ? 0 : context.raw; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return count + ' view' + (count !== 1 ? 's' : ''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -133,9 +209,13 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| display: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticks: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxRotation: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxRotation: 45, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| minRotation: 45, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| autoSkip: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxTicksLimit: 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxTicksLimit: 15, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| font: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size: 9 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| y: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -144,34 +224,62 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| color: 'rgba(200, 200, 200, 0.2)' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ticks: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| precision: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| precision: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stepSize: 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensure we only show integer values | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callback: function(value) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (value % 1 === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Initialize the chart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Initialize the chart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| initializeChart(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Set up vote functionality | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pageStatsContainer = document.getElementById('pageStatsContainer'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Set up vote functionality | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pageStatsContainer = document.getElementById('pageStatsContainer'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const upvoteBtn = document.getElementById('upvoteBtn'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const downvoteBtn = document.getElementById('downvoteBtn'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const upvoteCount = document.getElementById('upvoteCount'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const downvoteCount = document.getElementById('downvoteCount'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentTemplate = '{{ current_template }}'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentUrlPath = '{{ current_url_path }}'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Toggle container on click of the handle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleElement = pageStatsContainer.querySelector('.flex.justify-center'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (handleElement) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleElement.addEventListener('click', function(e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pageStatsContainer.classList.contains('translate-y-0')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.remove('translate-y-0'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.add('translate-y-[calc(100%-40px)]'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.remove('translate-y-[calc(100%-40px)]'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.add('translate-y-0'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add touch support for mobile devices | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.addEventListener('touchstart', function(e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pageStatsContainer.classList.contains('translate-y-0')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.remove('translate-y-0'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.add('translate-y-[calc(100%-40px)]'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.remove('translate-y-[calc(100%-40px)]'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.add('translate-y-0'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Only handle touch events on the handle element | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (e.target.closest('.flex.justify-center')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pageStatsContainer.classList.contains('translate-y-0')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.remove('translate-y-0'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.add('translate-y-[calc(100%-40px)]'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.remove('translate-y-[calc(100%-40px)]'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageStatsContainer.classList.add('translate-y-0'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -189,14 +297,28 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return cookieValue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let cookieValue = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (document.cookie && document.cookie !== '') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const cookies = document.cookie.split(';'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < cookies.length; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const cookie = cookies[i].trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (cookie.substring(0, name.length + 1) === (name + '=')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return cookieValue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const csrftoken = getCookie('csrftoken'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Vote submission handler | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Vote submission handler | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function submitVote(voteType) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const formData = new FormData(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('template_name', currentTemplate); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('url_path', currentUrlPath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('vote_type', voteType); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetch('{% url "page_vote" %}', { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -226,15 +348,21 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Event listeners for vote buttons | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Event listeners for vote buttons | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| upvoteBtn.addEventListener('click', function(e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.stopPropagation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| submitVote('upvote'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.stopPropagation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| submitVote('upvote'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| downvoteBtn.addEventListener('click', function(e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.stopPropagation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| submitVote('downvote'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.stopPropagation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| submitVote('downvote'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+351
to
365
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Duplicate Vote Submission Calls Proposed Diff for Upvote Button: -upvoteBtn.addEventListener('click', function(e) {
- e.stopPropagation();
- submitVote('upvote');
- e.stopPropagation();
- submitVote('upvote');
-});
+upvoteBtn.addEventListener('click', function(e) {
+ e.stopPropagation();
+ submitVote('upvote');
+});Proposed Diff for Downvote Button: -downvoteBtn.addEventListener('click', function(e) {
- e.stopPropagation();
- submitVote('downvote');
- e.stopPropagation();
- submitVote('downvote');
-});
+downvoteBtn.addEventListener('click', function(e) {
+ e.stopPropagation();
+ submitVote('downvote');
+});📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
366
to
+367
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extraneous Closing Bracket |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </script> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Duplicate DOM Element Declaration
The
pageStatsContainerelement is queried twice (lines 247 and 249). This duplication can lead to confusion and potential future issues. Please remove the redundant declaration.