| | const TPL = `<div style="padding: 10px; border-top: 1px solid var(--main-border-color); contain: none;"> |
---|
| | <strong>Moodlog Highlighting Applied</strong> |
---|
| | </div>`; |
---|
| | |
---|
| | class MoodlogHighlighterWidget extends api.NoteContextAwareWidget { |
---|
| | static get parentWidget() { |
---|
| | //console.log("MDLG: Getting parent widget: center-pane"); |
---|
| | return 'center-pane'; |
---|
| | } |
---|
| | |
---|
| | get position() { |
---|
| | //console.log("MDLG: Setting position: 100"); |
---|
| | return 100; |
---|
| | } |
---|
| | |
---|
| | isEnabled() { |
---|
| | const enabled = super.isEnabled() |
---|
| | && this.note.type === 'text' |
---|
| | && this.note.hasLabel('moodlog'); |
---|
| | //console.log(`MDLG: isEnabled: ${enabled}`); |
---|
| | return enabled; |
---|
| | } |
---|
| | |
---|
| | doRender() { |
---|
| | //console.log("MDLG: Rendering widget..."); |
---|
| | this.$widget = $(TPL); |
---|
| | //console.log("MDLG: Widget rendered:", this.$widget); |
---|
| | return this.$widget; |
---|
| | } |
---|
| | |
---|
| | async refreshWithNote(note) { |
---|
| | //console.log("MDLG: Refreshing with note:", note); |
---|
| | const { content } = await note.getNoteComplement(); |
---|
| | //console.log("MDLG: Note content fetched:", content); |
---|
| | |
---|
| | // Check if content is fetched properly |
---|
| | if (!content) { |
---|
| | //console.log("MDLG: No content fetched. Exiting refresh."); |
---|
| | return; |
---|
| | } |
---|
| | |
---|
| | const highlightedContent = this.applyHighlighting(content); |
---|
| | //console.log("MDLG: Highlighted content:", highlightedContent); |
---|
| | |
---|
| | if (highlightedContent !== content) { |
---|
| | //console.log("MDLG: Updating note content with highlighted version"); |
---|
| | |
---|
| | // Use the setNoteContent function to update the note content |
---|
| | try { |
---|
| | await setNoteContent(note.noteId, highlightedContent); |
---|
| | //console.log("MDLG: Content updated with highlighted version"); |
---|
| | } catch (error) { |
---|
| | //console.error("MDLG: Error updating content:", error); |
---|
| | } |
---|
| | } else { |
---|
| | //console.log("MDLG: No changes to content, skipping update."); |
---|
| | } |
---|
| | } |
---|
| | |
---|
| | |
---|
| | applyHighlighting(content) { |
---|
| | //console.log("MDLG: Applying highlighting to content..."); |
---|
| | |
---|
| | // Replace <br> with \n, then remove all other HTML tags |
---|
| | const plainTextContent = content.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]*>/g, ' '); |
---|
| | //console.log("MDLG: Stripped content:", plainTextContent); |
---|
| | |
---|
| | // Combined regex for date & time |
---|
| | const dateTimePattern = /([1-2]\d{3}[-/.](0?[1-9]|1[0-2])[-/.](0[1-9]|[12]\d|3[01]))\s+(\d{1,2}:\d{2})/g; |
---|
| | const projectPattern = /\[\S+?\]/g; |
---|
| | const contextPattern = /(\s|^)(@\S+)/g; |
---|
| | const hashtagPattern = /(\s|^)(#\S+)/g; |
---|
| | const positivePattern = /(\s|^)(\+\S+)/g; |
---|
| | const negativePattern = /(\s|^)(-\S+)/g; |
---|
| | |
---|
| | // Escape HTML characters to prevent issues with replacements |
---|
| | function escapeHtml(str) { |
---|
| | return str.replace(/[&<>"']/g, function (char) { |
---|
| | return { |
---|
| | '&': '&', |
---|
| | '<': '<', |
---|
| | '>': '>', |
---|
| | '"': '"', |
---|
| | "'": ''' |
---|
| | }[char]; |
---|
| | }); |
---|
| | } |
---|
| | |
---|
| | // Helper function to map the number to a colour based on the gradient |
---|
| | function getProjectColour(number) { |
---|
| | const minColor = { r: 107, g: 109, b: 229 }; // #6b6de5 |
---|
| | const maxColor = { r: 70, g: 226, b: 96 }; // #46e260 |
---|
| | |
---|
| | const ratio = number / 9; // since we are working with 0-9 |
---|
| | |
---|
| | // Interpolate the RGB values between minColor and maxColor |
---|
| | const r = Math.round(minColor.r + ratio * (maxColor.r - minColor.r)); |
---|
| | const g = Math.round(minColor.g + ratio * (maxColor.g - minColor.g)); |
---|
| | const b = Math.round(minColor.b + ratio * (maxColor.b - minColor.b)); |
---|
| | |
---|
| | return `rgb(${r}, ${g}, ${b})`; |
---|
| | } |
---|
| | |
---|
| | // Process each line of the plain text content |
---|
| | let highlightedLines = plainTextContent.split("\n").map(line => { |
---|
| | //console.log("MDLG: Processing line:", line); |
---|
| | |
---|
| | // Apply combined date & time highlight |
---|
| | line = line.replace(dateTimePattern, `<span style="color: rgb(188, 55, 237);">$1</span> <span style="color: rgb(188, 55, 237);">$4</span>`); |
---|
| | |
---|
| | // Apply other highlights |
---|
| | line = line.replace(projectPattern, (match) => { |
---|
| | // Extract the number inside square brackets |
---|
| | const number = parseInt(match.match(/\d+/)[0], 10); |
---|
| | const colour = getProjectColour(number); |
---|
| | return `<span style="color: ${colour}; font-weight: bold;">${escapeHtml(match)}</span>`; |
---|
| | }); |
---|
| | |
---|
| | // Apply other highlights |
---|
| | //line = line.replace(projectPattern, `<span style="color: rgb(224, 218, 36); font-weight: bold;">$&</span>`); |
---|
| | line = line.replace(contextPattern, (_, space, tag) => `${space}<span style="color: rgb(255 165 10);">${escapeHtml(tag)}</span>`); |
---|
| | line = line.replace(hashtagPattern, (_, space, tag) => `${space}<span style="color: rgb(41, 229, 242);">${escapeHtml(tag)}</span>`); |
---|
| | line = line.replace(positivePattern, (_, space, tag) => `${space}<span style="color: rgb(44, 227, 34);">${escapeHtml(tag)}</span>`); |
---|
| | line = line.replace(negativePattern, (_, space, tag) => `${space}<span style="color: rgb(230, 59, 44);">${escapeHtml(tag)}</span>`); |
---|
| | |
---|
| | return line.trim(); |
---|
| | }); |
---|
| | |
---|
| | // Join lines with proper <br> handling |
---|
| | let finalContent = highlightedLines.join("<br>"); |
---|
| | |
---|
| | //console.log("MDLG: Highlighted content:", finalContent); |
---|
| | return finalContent; |
---|
| | } |
---|
| | |
---|
| | |
---|
| | |
---|
| | |
---|
| | async entitiesReloadedEvent({ loadResults }) { |
---|
| | //console.log("MDLG: Entities reloaded event triggered"); |
---|
| | if (loadResults.isNoteContentReloaded(this.noteId)) { |
---|
| | //console.log("MDLG: Note content reloaded, refreshing widget..."); |
---|
| | //this.refresh(); |
---|
| | } else { |
---|
| | //console.log("MDLG: No content reload detected."); |
---|
| | } |
---|
| | } |
---|
| | |
---|
| | |
---|
| | } |
---|
| | |
---|
| | console.log("MDLG: Starting Moodlog Highlighter Widget"); |
---|
| | module.exports = MoodlogHighlighterWidget; |
---|
| | |
---|
| | function setNoteContent(noteId, content) { |
---|
| | /*const noteElement = document.querySelector(`note-detail-readonly-text-content`); |
---|
| | |
---|
| | if (noteElement) { |
---|
| | noteElement.innerHTML = content; // Update the displayed content |
---|
| | console.log(`MDLG: Updated note ${noteId} in the DOM.`); |
---|
| | } else { |
---|
| | console.warn(`MDLG: Note element with data-note-id='${noteId}' not found.`); |
---|
| | }*/ |
---|
| | return api.runOnBackend((id, data) => api.getNote(id).setContent(data), [noteId, content]); |
---|
| | } |
---|
| | |
---|
| | |