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]);
}