I am attempting to load a HTML code into my Canvas shell to create a Dissertation Calculator (completion generator) for my doctoral students. I am running into some formatting issues and believe it may be due to something blocking me from the IT side. I am pasting the code below, but based on the instructions I have, it not be working due to perhaps one of the following:
- Security Restrictions (Content Security Policy - CSP): Canvas environments often have strict Content Security Policies in place. These policies can block external resources like the Tailwind CSS CDN (https://cdn.tailwindcss.com">) or even inline JavaScript if they're not explicitly whitelisted. The current code uses an external CDN for Tailwind and inline JavaScript.
- iFrame Sandboxing: If you're embedding this HTML in an iFrame, the iFrame's sandbox attributes might be preventing scripts from running or certain elements from loading.
- HTML Sanitization: Canvas might be stripping out or modifying certain HTML tags or attributes that it deems unsafe or unsupported, which could break the layout or functionality.
- Specific Embedding Methods: Canvas might require a specific method for embedding custom HTML, such as using a "File Upload" to host the HTML and then linking to it, or using their "Embed Code" feature in a particular way.
Here is the code:
<!DOCTYPE</SPAN> html>
<</SPAN>html lang="en">
<</SPAN>head>
<</SPAN>meta charset="UTF-8">
<</SPAN>meta name="viewport" content="width=device-width, initial-scale=1.0">
<</SPAN>title>Dissertation Calculator</</SPAN>title>
<</SPAN>style>
body {
font-family: 'Inter', sans-serif;
background-color: #f0f4f8; /* Light blue-grey background */
}
.progress-bar-inner {
transition: width 0.3s ease-in-out;
}
</</SPAN>style>
</</SPAN>head>
<</SPAN>body class="min-h-screen flex flex-col items-center justify-center p-4">
<</SPAN>div class="bg-white p-8 rounded-lg shadow-xl w-full max-w-4xl border border-gray-200">
<</SPAN>h1 class="text-4xl font-bold text-center text-indigo-700 mb-8">Dissertation Progress Calculator</</SPAN>h1>
<</SPAN>div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
<</SPAN>div class="flex flex-col">
<</SPAN>label for="startDate" class="text-gray-700 font-semibold mb-2">Start Date:</</SPAN>label>
<</SPAN>input type="date" id="startDate" class="p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</</SPAN>div>
<</SPAN>div class="flex flex-col">
<</SPAN>label for="targetDate" class="text-gray-700 font-semibold mb-2">Target Completion Date:</</SPAN>label>
<</SPAN>input type="date" id="targetDate" class="p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</</SPAN>div>
<</SPAN>div class="flex flex-col">
<</SPAN>label for="totalWordCount" class="text-gray-700 font-semibold mb-2">Target Total Word Count:</</SPAN>label>
<</SPAN>input type="number" id="totalWordCount" class="p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g., 50000">
</</SPAN>div>
</</SPAN>div>
<</SPAN>div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8 text-center bg-indigo-50 p-6 rounded-lg border border-indigo-200">
<</SPAN>div>
<</SPAN>p class="text-lg text-indigo-800 font-medium">Total Weeks:</</SPAN>p>
<</SPAN>p id="totalWeeks" class="text-3xl font-bold text-indigo-900 mt-1">0</</SPAN>p>
</</SPAN>div>
<</SPAN>div>
<</SPAN>p class="text-lg text-indigo-800 font-medium">Words Per Week (Target):</</SPAN>p>
<</SPAN>p id="wordsPerWeek" class="text-3xl font-bold text-indigo-900 mt-1">0</</SPAN>p>
</</SPAN>div>
</</SPAN>div>
<</SPAN>div class="mb-8 border-t border-gray-200 pt-8">
<</SPAN>h2 class="text-2xl font-bold text-indigo-700 mb-6">Chapters/Sections</</SPAN>h2>
<</SPAN>div id="chaptersContainer" class="space-y-6">
</</SPAN>div>
<</SPAN>button id="addChapterBtn" class="mt-6 px-6 py-3 bg-indigo-600 text-white font-semibold rounded-md shadow-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors duration-200">
+ Add Chapter/Section
</</SPAN>button>
</</SPAN>div>
<</SPAN>div class="border-t border-gray-200 pt-8 mt-8">
<</SPAN>h2 class="text-2xl font-bold text-indigo-700 mb-4">Overall Dissertation Progress</</SPAN>h2>
<</SPAN>div class="w-full bg-gray-200 rounded-full h-8 mb-4 overflow-hidden">
<</SPAN>div id="overallProgressBar" class="progress-bar-inner bg-green-500 h-full text-white text-right pr-4 flex items-center justify-end rounded-full" style="width: 0%;">0%</</SPAN>div>
</</SPAN>div>
<</SPAN>p class="text-gray-600 text-sm">Completed Word Count: <</SPAN>span id="completedWordCount">0</</SPAN>span> / <</SPAN>span id="displayTotalWordCount">0</</SPAN>span></</SPAN>p>
</</SPAN>div>
<</SPAN>div class="mt-12 p-6 bg-yellow-50 rounded-lg border border-yellow-200">
<</SPAN>h2 class="text-2xl font-bold text-yellow-800 mb-4">Dissertation Tips</</SPAN>h2>
<</SPAN>ul class="list-disc list-inside text-gray-700 space-y-2">
<</SPAN>li>Break down your dissertation into manageable chunks.</</SPAN>li>
<</SPAN>li>Set realistic daily or weekly word count goals.</</SPAN>li>
<</SPAN>li>Schedule dedicated writing time and stick to it.</</SPAN>li>
<</SPAN>li>Don't aim for perfection in the first draft; just get words on the page.</</SPAN>li>
<</SPAN>li>Seek feedback from your advisor and peers regularly.</</SPAN>li>
<</SPAN>li>Take breaks to avoid burnout and maintain productivity.</</SPAN>li>
</</SPAN>ul>
</</SPAN>div>
</</SPAN>div>
<</SPAN>script>
// DOM Elements
const startDateInput = document.getElementById('startDate');
const targetDateInput = document.getElementById('targetDate');
const totalWordCountInput = document.getElementById('totalWordCount');
const totalWeeksDisplay = document.getElementById('totalWeeks');
const wordsPerWeekDisplay = document.getElementById('wordsPerWeek');
const chaptersContainer = document.getElementById('chaptersContainer');
const addChapterBtn = document.getElementById('addChapterBtn');
const overallProgressBar = document.getElementById('overallProgressBar');
const completedWordCountDisplay = document.getElementById('completedWordCount');
const displayTotalWordCount = document.getElementById('displayTotalWordCount');
let chapterCount = 0; // To keep track of chapters and assign unique IDs
// Function to calculate weeks between two dates
function getWeeksBetweenDates(start, end) {
if (!start || !end) return 0;
const startDate = new Date(start);
const endDate = new Date(end);
const millisecondsPerWeek = 1000 * 60 * 60 * 24 * 7;
const diffMilliseconds = endDate.getTime() - startDate.getTime();
return Math.max(0, Math.floor(diffMilliseconds / millisecondsPerWeek));
}
// Function to update calculations
function updateCalculations() {
const startDate = startDateInput.value;
const targetDate = targetDateInput.value;
const totalWordCount = parseInt(totalWordCountInput.value) || 0;
const totalWeeks = getWeeksBetweenDates(startDate, targetDate);
totalWeeksDisplay.textContent = totalWeeks;
const wordsPerWeek = totalWeeks > 0 ? Math.ceil(totalWordCount / totalWeeks) : 0;
wordsPerWeekDisplay.textContent = wordsPerWeek;
// Update overall progress
updateOverallProgress();
}
// Function to create a new chapter element
function createChapterElement(id) {
const chapterDiv = document.createElement('div');
chapterDiv.className = 'chapter-item bg-gray-50 p-6 rounded-lg shadow-sm border border-gray-200';
chapterDiv.innerHTML = `
Chapter/Section ${id}
×
${id}" class="chapter-name p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-400" placeholder="e.g., Introduction">
${id}" class="target-chapter-word-count p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-400" placeholder="e.g., 5000">
${id}" class="actual-chapter-word-count p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-400" value="0">
${id}" class="progress-bar-inner bg-blue-500 h-full text-white text-right pr-3 flex items-center justify-end rounded-full" style="width: 0%;">0%
`;
chaptersContainer.appendChild(chapterDiv);
// Add event listeners to the new inputs
const targetChapterWC = chapterDiv.querySelector(`#targetChapterWordCount-${id}`);
const actualChapterWC = chapterDiv.querySelector(`#actualChapterWordCount-${id}`);
const removeBtn = chapterDiv.querySelector('.remove-chapter-btn');
[targetChapterWC, actualChapterWC].forEach(input => {
input.addEventListener('input', () => updateChapterProgress(id));
input.addEventListener('input', updateOverallProgress); // Update overall on chapter changes
});
removeBtn.addEventListener('click', () => {
chapterDiv.remove();
updateOverallProgress(); // Update overall progress after removing a chapter
});
// Initial update for the new chapter
updateChapterProgress(id);
}
// Function to update progress for a specific chapter
function updateChapterProgress(id) {
const target = parseInt(document.getElementById(`targetChapterWordCount-${id}`).value) || 0;
const actual = parseInt(document.getElementById(`actualChapterWordCount-${id}`).value) || 0;
const progressBar = document.getElementById(`chapterProgressBar-${id}`);
let percentage = 0;
if (target > 0) {
percentage = Math.min(100, (actual / target) * 100);
}
progressBar.style.width = `${percentage}%`;
progressBar.textContent = `${Math.round(percentage)}%`;
// Change color based on progress
if (percentage >= 100) {
progressBar.classList.remove('bg-blue-500');
progressBar.classList.add('bg-green-500');
} else {
progressBar.classList.remove('bg-green-500');
progressBar.classList.add('bg-blue-500');
}
}
// Function to update overall dissertation progress
function updateOverallProgress() {
const totalTargetWordCount = parseInt(totalWordCountInput.value) || 0;
displayTotalWordCount.textContent = totalTargetWordCount; // Update the display
let totalActualCompletedWords = 0;
const chapterActualWordCounts = document.querySelectorAll('.actual-chapter-word-count');
chapterActualWordCounts.forEach(input => {
totalActualCompletedWords += parseInt(input.value) || 0;
});
completedWordCountDisplay.textContent = totalActualCompletedWords;
let overallPercentage = 0;
if (totalTargetWordCount > 0) {
overallPercentage = Math.min(100, (totalActualCompletedWords / totalTargetWordCount) * 100);
}
overallProgressBar.style.width = `${overallPercentage}%`;
overallProgressBar.textContent = `${Math.round(overallPercentage)}%`;
// Change color based on progress
if (overallPercentage >= 100) {
overallProgressBar.classList.remove('bg-red-500', 'bg-yellow-500', 'bg-blue-500');
overallProgressBar.classList.add('bg-green-500');
} else if (overallPercentage > 50) {
overallProgressBar.classList.remove('bg-red-500', 'bg-yellow-500', 'bg-green-500');
overallProgressBar.classList.add('bg-blue-500');
} else if (overallPercentage > 25) {
overallProgressBar.classList.remove('bg-red-500', 'bg-blue-500', 'bg-green-500');
overallProgressBar.classList.add('bg-yellow-500');
} else {
overallProgressBar.classList.remove('bg-yellow-500', 'bg-blue-500', 'bg-green-500');
overallProgressBar.classList.add('bg-red-500');
}
}
// Event Listeners for main inputs
startDateInput.addEventListener('input', updateCalculations);
targetDateInput.addEventListener('input', updateCalculations);
totalWordCountInput.addEventListener('input', updateCalculations);
totalWordCountInput.addEventListener('input', updateOverallProgress); // Also update overall progress if total changes
// Event Listener for Add Chapter button
addChapterBtn.addEventListener('click', () => {
chapterCount++;
createChapterElement(chapterCount);
});
// Initial setup on page load
document.addEventListener('DOMContentLoaded', () => {
// Set default dates (e.g., today and 6 months from now)
const today = new Date();
startDateInput.valueAsDate = today;
const sixMonthsLater = new Date();
sixMonthsLater.setMonth(today.getMonth() + 6);
targetDateInput.valueAsDate = sixMonthsLater;
// Trigger initial calculations
updateCalculations();
updateOverallProgress(); // Ensure overall progress is calculated on load too
});
// Add an initial chapter
document.addEventListener('DOMContentLoaded', () => {
if (chaptersContainer.children.length === 0) {
chapterCount++;
createChapterElement(chapterCount);
}
});
</</SPAN>script>
</</SPAN>body>
</</SPAN>html>