diff --git a/src/app/course/[courseName]/calendar/day/getStatus.tsx b/src/app/course/[courseName]/calendar/day/getStatus.tsx index 6caf87a..23f5482 100644 --- a/src/app/course/[courseName]/calendar/day/getStatus.tsx +++ b/src/app/course/[courseName]/calendar/day/getStatus.tsx @@ -108,6 +108,12 @@ export const getStatus = ({ markdownToHTMLSafe({ markdownString: assignment.description, settings, + replaceText: [ + { + source: "insert_github_classroom_url", + destination: assignment.githubClassroomAssignmentShareLink || "", + }, + ], }), canvasAssignment.description ); diff --git a/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx b/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx index 03bbc88..7c25fa1 100644 --- a/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx +++ b/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx @@ -59,7 +59,15 @@ export default function AssignmentPreview({

- +

diff --git a/src/components/MarkdownDisplay.tsx b/src/components/MarkdownDisplay.tsx index c1c93cb..9670757 100644 --- a/src/components/MarkdownDisplay.tsx +++ b/src/components/MarkdownDisplay.tsx @@ -6,9 +6,14 @@ import { LocalCourseSettings } from "@/features/local/course/localCourseSettings export default function MarkdownDisplay({ markdown, className = "", + replaceText = [], }: { markdown: string; className?: string; + replaceText?: { + source: string; + destination: string; + }[]; }) { const { data: settings } = useLocalCourseSettingsQuery(); return ( @@ -17,6 +22,7 @@ export default function MarkdownDisplay({ markdown={markdown} settings={settings} className={className} + replaceText={replaceText} /> ); @@ -26,16 +32,25 @@ function DangerousInnerMarkdown({ markdown, settings, className, + replaceText, }: { markdown: string; settings: LocalCourseSettings; className: string; + replaceText: { + source: string; + destination: string; + }[]; }) { return (
); diff --git a/src/features/canvas/services/canvasAssignmentService.ts b/src/features/canvas/services/canvasAssignmentService.ts index 43da076..d40ca1b 100644 --- a/src/features/canvas/services/canvasAssignmentService.ts +++ b/src/features/canvas/services/canvasAssignmentService.ts @@ -32,16 +32,14 @@ export const canvasAssignmentService = { const content = markdownToHTMLSafe({ markdownString: localAssignment.description, settings, + replaceText: [ + { + source: "insert_github_classroom_url", + destination: localAssignment.githubClassroomAssignmentShareLink || "", + }, + ], }); - const contentWithClassroomLinks = - localAssignment.githubClassroomAssignmentShareLink - ? content.replaceAll( - "insert_github_classroom_url", - localAssignment.githubClassroomAssignmentShareLink - ) - : content; - const body = { assignment: { name: localAssignment.name, @@ -51,7 +49,7 @@ export const canvasAssignmentService = { allowed_extensions: localAssignment.allowedFileUploadExtensions.map( (e) => e.toString() ), - description: contentWithClassroomLinks, + description: content, due_at: getDateFromString(localAssignment.dueAt)?.toISOString(), lock_at: localAssignment.lockAt && @@ -90,6 +88,13 @@ export const canvasAssignmentService = { description: markdownToHTMLSafe({ markdownString: localAssignment.description, settings, + replaceText: [ + { + source: "insert_github_classroom_url", + destination: + localAssignment.githubClassroomAssignmentShareLink || "", + }, + ], }), due_at: getDateFromString(localAssignment.dueAt)?.toISOString(), lock_at: diff --git a/src/services/htmlMarkdownUtils.ts b/src/services/htmlMarkdownUtils.ts index 5686571..ee9a337 100644 --- a/src/services/htmlMarkdownUtils.ts +++ b/src/services/htmlMarkdownUtils.ts @@ -90,14 +90,12 @@ export function markdownToHTMLSafe({ replaceText?: { source: string; destination: string }[]; }) { const html = markdownToHtmlNoImages(markdownString); - if (convertImages) return convertImagesToCanvasImages(html, settings); - - const replacedHtml = replaceText.reduce( (acc, { source, destination }) => acc.replaceAll(source, destination), html ); - // return html; + + if (convertImages) return convertImagesToCanvasImages(replacedHtml, settings); return replacedHtml; } diff --git a/src/services/utils/htmlIsCloseEnough.ts b/src/services/utils/htmlIsCloseEnough.ts index b9655ad..5decd4b 100644 --- a/src/services/utils/htmlIsCloseEnough.ts +++ b/src/services/utils/htmlIsCloseEnough.ts @@ -1,6 +1,7 @@ const scriptRegex = //g; const linkTagRegex = /]*>/g; -const htmlAttribute = /\s+\w+="[^"]*"|\s+\w+='[^']*'|\s+\w+=[^\s>]+/g; +const nonHrefAttribute = + /\s+(?!href\s*=)\w+="[^"]*"|\s+(?!href\s*=)\w+='[^']*'|\s+(?!href\s*=)\w+=[^\s>]+/g; function replaceUnicodeEscapes(input: string) { return input.replace(/\\u[\dA-Fa-f]{4}/g, (match) => { @@ -14,7 +15,7 @@ export const removeHtmlDetails = (html: string) => { return withoutUnicode .replaceAll(scriptRegex, "") .replaceAll(linkTagRegex, "") - .replaceAll(htmlAttribute, "") + .replaceAll(nonHrefAttribute, "") .replaceAll(/\\"/g, '"') .replaceAll(/\s/g, "") .replaceAll(//g, "
") @@ -32,5 +33,45 @@ export const removeHtmlDetails = (html: string) => { export const htmlIsCloseEnough = (html1: string, html2: string) => { const simple1 = removeHtmlDetails(html1); const simple2 = removeHtmlDetails(html2); + + if (simple1 !== simple2) { + const len1 = simple1.length; + const len2 = simple2.length; + const maxLen = Math.max(len1, len2); + + let firstDiff = -1; + const diffs: Array<{ index: number; a: string; b: string }> = []; + + for (let i = 0; i < maxLen && diffs.length < 10; i++) { + const a = simple1[i] ?? "∅"; + const b = simple2[i] ?? "∅"; + if (a !== b) { + if (firstDiff === -1) firstDiff = i; + diffs.push({ index: i, a, b }); + } + } + + const ctx = 30; + const start = Math.max(0, (firstDiff === -1 ? 0 : firstDiff) - ctx); + const end1 = Math.min(len1, (firstDiff === -1 ? 0 : firstDiff) + ctx); + const end2 = Math.min(len2, (firstDiff === -1 ? 0 : firstDiff) + ctx); + + const mark = (s: string, sStart: number, idx: number, sEnd: number) => { + if (idx < 0) return s.slice(sStart, sEnd); + const before = s.slice(sStart, idx); + const ch = s[idx] ?? "∅"; + const after = s.slice(idx + 1, sEnd); + return `${before}[${ch}]${after}`; + }; + + console.log("htmlIsCloseEnough: differences detected"); + console.log(`len1=${len1}, len2=${len2}`); + if (firstDiff !== -1) { + console.log(`firstDiffAt=${firstDiff}`); + console.log("s1:", mark(simple1, start, firstDiff, end1)); + console.log("s2:", mark(simple2, start, firstDiff, end2)); + } + console.log("first 10 diffs:", diffs); + } return simple1 === simple2; };