diff --git a/api/claude-service.ts b/api/claude-service.ts
index 7021e25..fa784ee 100644
--- a/api/claude-service.ts
+++ b/api/claude-service.ts
@@ -1,4 +1,4 @@
-import { Notice } from 'obsidian';
+import { Notice, requestUrl } from 'obsidian';
import SpaceforgePlugin from '../main';
import { MCQQuestion, MCQSet } from '../models/mcq';
import { IMCQGenerationService } from './mcq-generation-service';
@@ -89,7 +89,8 @@ export class ClaudeService implements IMCQGenerationService {
console.log(`Making API request to Claude using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch('https://api.anthropic.com/v1/messages', {
+ const response = await requestUrl({
+ url: 'https://api.anthropic.com/v1/messages',
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -106,13 +107,13 @@ export class ClaudeService implements IMCQGenerationService {
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json || { message: response.text };
console.error('Claude API error:', response.status, errorData);
throw new Error(`API request failed (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.content || !data.content.length || !data.content[0].text) {
console.error('Invalid API response format from Claude:', data);
throw new Error('Invalid API response format from Claude - missing content');
diff --git a/api/gemini-service.ts b/api/gemini-service.ts
index f0ae305..38cfc13 100644
--- a/api/gemini-service.ts
+++ b/api/gemini-service.ts
@@ -1,4 +1,4 @@
-import { Notice } from 'obsidian';
+import { Notice, requestUrl } from 'obsidian';
import SpaceforgePlugin from '../main';
import { MCQQuestion, MCQSet } from '../models/mcq';
import { IMCQGenerationService } from './mcq-generation-service';
@@ -92,7 +92,8 @@ export class GeminiService implements IMCQGenerationService {
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
try {
- const response = await fetch(apiUrl, {
+ const response = await requestUrl({
+ url: apiUrl,
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -108,14 +109,14 @@ export class GeminiService implements IMCQGenerationService {
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json;
console.error('Gemini API error:', response.status, errorData);
const errorMessage = errorData?.error?.message || errorData?.message || 'Unknown error';
throw new Error(`API request failed (${response.status}): ${errorMessage}`);
}
- const data = await response.json();
+ const data = response.json;
// Gemini response structure: data.candidates[0].content.parts[0].text
if (!data.candidates || !data.candidates.length || !data.candidates[0].content || !data.candidates[0].content.parts || !data.candidates[0].content.parts.length || !data.candidates[0].content.parts[0].text) {
console.error('Invalid API response format from Gemini:', data);
diff --git a/api/ollama-service.ts b/api/ollama-service.ts
index f024892..9217e5c 100644
--- a/api/ollama-service.ts
+++ b/api/ollama-service.ts
@@ -1,4 +1,4 @@
-import { Notice } from 'obsidian';
+import { Notice, requestUrl } from 'obsidian';
import SpaceforgePlugin from '../main';
import { MCQQuestion, MCQSet } from '../models/mcq';
import { IMCQGenerationService } from './mcq-generation-service';
@@ -89,7 +89,8 @@ export class OllamaService implements IMCQGenerationService {
console.log(`Making API request to Ollama at ${apiUrl} using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch(`${apiUrl}/api/chat`, { // Common Ollama chat endpoint
+ const response = await requestUrl({
+ url: `${apiUrl}/api/chat`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -104,13 +105,13 @@ export class OllamaService implements IMCQGenerationService {
})
});
- if (!response.ok) {
- const errorText = await response.text();
+ if (response.status !== 200) {
+ const errorText = response.text;
console.error('Ollama API error:', response.status, errorText);
throw new Error(`API request failed (${response.status}): ${errorText}`);
}
- const data = await response.json();
+ const data = response.json;
// Ollama's non-streaming chat response structure is typically { model, created_at, message: { role, content }, done }
if (!data.message || !data.message.content) {
console.error('Invalid API response format from Ollama:', data);
diff --git a/api/openai-service.ts b/api/openai-service.ts
index 3f98584..2f8c6e7 100644
--- a/api/openai-service.ts
+++ b/api/openai-service.ts
@@ -1,4 +1,4 @@
-import { Notice } from 'obsidian';
+import { Notice, requestUrl } from 'obsidian';
import SpaceforgePlugin from '../main';
import { MCQQuestion, MCQSet } from '../models/mcq';
import { IMCQGenerationService } from './mcq-generation-service';
@@ -89,7 +89,8 @@ export class OpenAIService implements IMCQGenerationService {
console.log(`Making API request to OpenAI using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
+ const response = await requestUrl({
+ url: 'https://api.openai.com/v1/chat/completions',
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -104,13 +105,13 @@ export class OpenAIService implements IMCQGenerationService {
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json || { message: response.text };
console.error('OpenAI API error:', response.status, errorData);
throw new Error(`API request failed (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.choices || !data.choices.length || !data.choices[0].message || !data.choices[0].message.content) {
console.error('Invalid API response format from OpenAI:', data);
throw new Error('Invalid API response format from OpenAI - missing content');
diff --git a/api/openrouter-service.ts b/api/openrouter-service.ts
index 2a98817..3993480 100644
--- a/api/openrouter-service.ts
+++ b/api/openrouter-service.ts
@@ -1,4 +1,4 @@
-import { Notice } from 'obsidian'; // Removed TFile as it wasn't used
+import { Notice, requestUrl } from 'obsidian'; // Removed TFile as it wasn't used
import SpaceforgePlugin from '../main';
import { MCQQuestion, MCQSet } from '../models/mcq';
import { IMCQGenerationService } from './mcq-generation-service';
@@ -147,7 +147,8 @@ For example:
? settings.mcqBasicSystemPrompt
: settings.mcqAdvancedSystemPrompt;
- const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
+ const response = await requestUrl({
+ url: 'https://openrouter.ai/api/v1/chat/completions',
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -169,20 +170,19 @@ For example:
]
})
});
-
- if (!response.ok) {
- const errorText = await response.text();
- console.error('OpenRouter API error:', errorText);
- throw new Error(`API request failed (${response.status}): ${errorText}`);
+
+ if (response.status !== 200) {
+ console.error('OpenRouter API error:', response.text);
+ throw new Error(`API request failed (${response.status}): ${response.text}`);
}
-
- const data = await response.json();
-
+
+ const data = response.json;
+
if (!data.choices || !data.choices.length || !data.choices[0].message) {
console.error('Invalid API response format from OpenRouter:', data);
throw new Error('Invalid API response format from OpenRouter - missing choices');
}
-
+
return data.choices[0].message.content;
} catch (error) {
console.error('Error in OpenRouter API request:', error);
diff --git a/api/together-service.ts b/api/together-service.ts
index 79adbce..ca61e11 100644
--- a/api/together-service.ts
+++ b/api/together-service.ts
@@ -1,4 +1,4 @@
-import { Notice } from 'obsidian';
+import { Notice, requestUrl } from 'obsidian';
import SpaceforgePlugin from '../main';
import { MCQQuestion, MCQSet } from '../models/mcq';
import { IMCQGenerationService } from './mcq-generation-service';
@@ -89,7 +89,8 @@ export class TogetherService implements IMCQGenerationService {
console.log(`Making API request to Together AI using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch('https://api.together.xyz/v1/chat/completions', {
+ const response = await requestUrl({
+ url: 'https://api.together.xyz/v1/chat/completions',
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -105,13 +106,13 @@ export class TogetherService implements IMCQGenerationService {
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json || { message: response.text };
console.error('Together AI API error:', response.status, errorData);
throw new Error(`API request failed (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.choices || !data.choices.length || !data.choices[0].message || !data.choices[0].message.content) {
console.error('Invalid API response format from Together AI:', data);
throw new Error('Invalid API response format from Together AI - missing content');
diff --git a/main.js b/main.js
index 34a1d89..a857374 100644
--- a/main.js
+++ b/main.js
@@ -1234,6 +1234,7 @@ var ReviewModal = class extends import_obsidian2.Modal {
}
}
const infoText = contentEl.createDiv("review-info-text");
+ infoText.empty();
if (schedule) {
const file = this.app.vault.getAbstractFileByPath(this.path);
const fileName = file instanceof import_obsidian2.TFile ? file.basename : this.path;
@@ -1277,7 +1278,6 @@ var ReviewModal = class extends import_obsidian2.Modal {
onClose() {
const { contentEl } = this;
contentEl.empty();
- console.log("Review modal closed for path: " + this.path);
}
};
@@ -1929,11 +1929,7 @@ var ConsolidatedMCQModal = class extends import_obsidian5.Modal {
const progressPercent = Math.round((this.currentQuestionIndex + 1) / this.allQuestions.length * 100);
contentEl.setAttribute("data-progress", progressPercent.toString());
progressEl.setText(`Question ${this.currentQuestionIndex + 1} of ${this.allQuestions.length}`);
- const progressCounter = contentEl.createDiv();
- progressCounter.style.textAlign = "center";
- progressCounter.style.marginBottom = "12px";
- progressCounter.style.fontSize = "0.9em";
- progressCounter.style.color = "var(--mcq-text-muted)";
+ const progressCounter = contentEl.createDiv("mcq-progress-counter");
progressCounter.setText(`${this.allQuestions.length} questions from ${this.mcqSets.length} notes`);
const noteInfoEl = contentEl.createDiv("mcq-note-info");
noteInfoEl.setText(`Question from: ${this.allQuestions[this.currentQuestionIndex].fileName}`);
@@ -2178,10 +2174,7 @@ var ConsolidatedMCQModal = class extends import_obsidian5.Modal {
this.onComplete(results);
const { contentEl } = this;
contentEl.empty();
- const headerEl = contentEl.createEl("h2", { text: "MCQ Review Complete" });
- headerEl.style.color = "var(--mcq-primary)";
- headerEl.style.textAlign = "center";
- headerEl.style.marginBottom = "24px";
+ const headerEl = contentEl.createEl("h2", { text: "MCQ Review Complete", cls: "mcq-review-complete-header" });
const totalCorrectOverall = this.answers.filter((a) => a.correct && a.attempts <= 1).length;
const totalQuestionsOverall = this.allQuestions.length;
const overallScore = totalQuestionsOverall > 0 ? totalCorrectOverall / totalQuestionsOverall : 0;
@@ -2189,30 +2182,24 @@ var ConsolidatedMCQModal = class extends import_obsidian5.Modal {
const scoreEl = contentEl.createDiv("mcq-score");
const scoreTextEl = scoreEl.createDiv("mcq-score-text");
scoreTextEl.setText(`Overall Score: ${scorePercentOverall}%`);
- const performanceIndicator = scoreEl.createDiv();
- performanceIndicator.style.marginTop = "8px";
- performanceIndicator.style.fontSize = "1.1em";
+ const performanceIndicator = scoreEl.createDiv("mcq-performance-indicator");
if (scorePercentOverall >= 90) {
performanceIndicator.setText("\u{1F393} Excellent Performance!");
- performanceIndicator.style.color = "var(--mcq-correct)";
+ performanceIndicator.addClass("excellent");
} else if (scorePercentOverall >= 70) {
performanceIndicator.setText("\u{1F44D} Good Work!");
- performanceIndicator.style.color = "var(--mcq-primary)";
+ performanceIndicator.addClass("good");
} else if (scorePercentOverall >= 50) {
performanceIndicator.setText("\u{1F504} Keep Practicing");
- performanceIndicator.style.color = "var(--mcq-warning)";
+ performanceIndicator.addClass("needs-improvement");
} else {
performanceIndicator.setText("\u{1F4DA} More Review Recommended");
- performanceIndicator.style.color = "var(--mcq-text-muted)";
+ performanceIndicator.addClass("review-recommended");
}
- const statsEl = scoreEl.createDiv();
- statsEl.style.marginTop = "12px";
- statsEl.style.fontSize = "0.9em";
- statsEl.style.color = "var(--mcq-text-muted)";
+ const statsEl = scoreEl.createDiv("mcq-stats-summary");
statsEl.setText(`${totalCorrectOverall} correct out of ${totalQuestionsOverall} questions`);
const noteScoresEl = contentEl.createDiv("mcq-note-scores");
- const scoreHeading = noteScoresEl.createEl("h3", { text: "Scores by Note" });
- scoreHeading.style.marginTop = "20px";
+ const scoreHeading = noteScoresEl.createEl("h3", { text: "Scores by Note", cls: "mcq-note-scores-heading" });
const sortedNotes = Object.keys(noteScores).sort((a, b2) => noteScores[b2].score - noteScores[a].score);
for (const notePath of sortedNotes) {
const noteScore = noteScores[notePath];
@@ -2229,55 +2216,32 @@ var ConsolidatedMCQModal = class extends import_obsidian5.Modal {
cls: "mcq-note-score-value"
});
if (noteScore.score >= 0.7) {
- scoreTextValueEl.style.backgroundColor = "rgba(76, 175, 80, 0.1)";
- scoreTextValueEl.style.color = "var(--mcq-correct)";
- scoreTextValueEl.style.border = "1px solid var(--mcq-correct)";
+ scoreTextValueEl.addClass("high-score");
} else if (noteScore.score >= 0.5) {
- scoreTextValueEl.style.backgroundColor = "rgba(255, 152, 0, 0.1)";
- scoreTextValueEl.style.color = "var(--mcq-warning)";
- scoreTextValueEl.style.border = "1px solid var(--mcq-warning)";
+ scoreTextValueEl.addClass("medium-score");
} else {
- scoreTextValueEl.style.backgroundColor = "rgba(244, 67, 54, 0.1)";
- scoreTextValueEl.style.color = "var(--mcq-incorrect)";
- scoreTextValueEl.style.border = "1px solid var(--mcq-incorrect)";
+ scoreTextValueEl.addClass("low-score");
}
- const progressBar = noteScoreEl.createDiv();
- progressBar.style.height = "4px";
- progressBar.style.backgroundColor = "var(--background-modifier-border)";
- progressBar.style.borderRadius = "2px";
- progressBar.style.marginTop = "6px";
- progressBar.style.position = "relative";
- progressBar.style.overflow = "hidden";
- const progressFill = progressBar.createDiv();
- progressFill.style.position = "absolute";
- progressFill.style.left = "0";
- progressFill.style.top = "0";
- progressFill.style.height = "100%";
+ const progressBar = noteScoreEl.createDiv("mcq-progress-bar");
+ const progressFill = progressBar.createDiv("mcq-progress-fill");
progressFill.style.width = `${scorePercent}%`;
- progressFill.style.transition = "width 0.5s ease";
if (noteScore.score >= 0.7) {
- progressFill.style.backgroundColor = "var(--mcq-correct)";
+ progressFill.addClass("high-score");
} else if (noteScore.score >= 0.5) {
- progressFill.style.backgroundColor = "var(--mcq-warning)";
+ progressFill.addClass("medium-score");
} else {
- progressFill.style.backgroundColor = "var(--mcq-incorrect)";
+ progressFill.addClass("low-score");
}
}
const breakdownContainer = contentEl.createDiv("mcq-detailed-breakdown");
- breakdownContainer.style.marginTop = "24px";
breakdownContainer.createEl("h3", { text: "Detailed Question Breakdown" });
this.allQuestions.forEach((question, index) => {
const questionEl = breakdownContainer.createDiv("mcq-breakdown-item");
- questionEl.style.marginBottom = "12px";
- questionEl.style.padding = "8px";
- questionEl.style.border = "1px solid var(--background-modifier-border)";
- questionEl.style.borderRadius = "4px";
const questionHeader = questionEl.createDiv();
questionHeader.createSpan({ text: `Q${index + 1} (from ${question.fileName}): `, cls: "mcq-breakdown-q-header" });
questionHeader.createSpan({ text: question.question });
const userAnswer = this.answers.find((a) => a.questionIndex === index);
- const userAnswerTextEl = questionEl.createDiv();
- userAnswerTextEl.style.marginLeft = "10px";
+ const userAnswerTextEl = questionEl.createDiv("mcq-user-answer-text");
let userAnswerDisplay = "Not answered";
if (userAnswer && userAnswer.selectedAnswerIndex !== -1 && userAnswer.selectedAnswerIndex < question.choices.length) {
userAnswerDisplay = question.choices[userAnswer.selectedAnswerIndex];
@@ -2288,29 +2252,23 @@ var ConsolidatedMCQModal = class extends import_obsidian5.Modal {
const correctnessText = userAnswer.correct ? " (Correct)" : " (Incorrect)";
userAnswerTextEl.createSpan({ text: "Your answer: " });
const userAnswerSpan = userAnswerTextEl.createSpan({ text: userAnswerDisplay });
- const correctnessSpan = userAnswerTextEl.createSpan({ text: correctnessText });
- correctnessSpan.style.fontWeight = "bold";
+ const correctnessSpan = userAnswerTextEl.createSpan({ text: correctnessText, cls: "mcq-correctness-indicator" });
if (userAnswer.correct) {
- userAnswerSpan.style.color = "var(--mcq-correct)";
- correctnessSpan.style.color = "var(--mcq-correct)";
+ userAnswerSpan.addClass("correct");
+ correctnessSpan.addClass("correct");
} else {
- userAnswerSpan.style.color = "var(--mcq-incorrect)";
- correctnessSpan.style.color = "var(--mcq-incorrect)";
+ userAnswerSpan.addClass("incorrect");
+ correctnessSpan.addClass("incorrect");
}
} else {
userAnswerTextEl.createSpan({ text: "Your answer: " + userAnswerDisplay });
userAnswerTextEl.style.fontStyle = "italic";
}
- const correctAnswerEl = questionEl.createDiv();
- correctAnswerEl.style.marginLeft = "10px";
+ const correctAnswerEl = questionEl.createDiv("mcq-correct-answer");
correctAnswerEl.createSpan({ text: "Correct answer: " });
- const correctAnswerSpan = correctAnswerEl.createSpan({ text: question.choices[question.correctAnswerIndex] });
- correctAnswerSpan.style.color = "var(--mcq-correct-answer-text)";
- correctAnswerSpan.style.fontWeight = "bold";
+ correctAnswerEl.createSpan({ text: question.choices[question.correctAnswerIndex], cls: "mcq-correct-answer-text" });
});
- const closeBtn = contentEl.createEl("button", "mcq-close-btn");
- closeBtn.setText("Close");
- closeBtn.style.marginTop = "24px";
+ const closeBtn = contentEl.createEl("button", { cls: "mcq-close-btn", text: "Close" });
closeBtn.addEventListener("click", () => {
this.close();
});
@@ -2469,7 +2427,6 @@ var BatchReviewModal = class extends import_obsidian6.Modal {
this.allMCQSets,
(results) => {
this.results = results;
- console.log("Consolidated MCQ review complete with results:", results);
this.recordAllReviews(results).then(() => {
this.open();
this.showSummary();
@@ -2477,7 +2434,6 @@ var BatchReviewModal = class extends import_obsidian6.Modal {
}
);
consolidatedModal.open();
- console.log(`Opened consolidated MCQ modal with ${this.allMCQSets.length} MCQ sets`);
} catch (error) {
console.error("Error showing consolidated MCQ UI:", error);
new import_obsidian6.Notice("Error showing MCQ review. Falling back to manual review.");
@@ -3041,23 +2997,10 @@ var MCQModal = class extends import_obsidian8.Modal {
const existingAnswer = this.session.answers.find((a) => a.questionIndex === questionIndex);
if (existingAnswer && existingAnswer.attempts >= 2) {
const skipContainer = newQuestionContainer.createDiv("mcq-skip-container");
- skipContainer.style.marginBottom = "12px";
- skipContainer.style.textAlign = "right";
const skipButton = skipContainer.createEl("button", { text: "Show Answer & Continue", cls: "mcq-skip-button" });
- skipButton.style.backgroundColor = "var(--text-muted)";
- skipButton.style.color = "white";
- skipButton.style.padding = "4px 8px";
- skipButton.style.borderRadius = "4px";
- skipButton.style.cursor = "pointer";
- skipButton.style.border = "none";
skipButton.addEventListener("click", () => {
const correctIndex = question.correctAnswerIndex;
const correctAnswerDisplay = newQuestionContainer.createDiv("mcq-correct-answer-display");
- correctAnswerDisplay.style.backgroundColor = "rgba(76, 175, 80, 0.1)";
- correctAnswerDisplay.style.padding = "10px";
- correctAnswerDisplay.style.borderRadius = "4px";
- correctAnswerDisplay.style.marginBottom = "10px";
- correctAnswerDisplay.style.border = "1px solid #4caf50";
const correctLabel = correctAnswerDisplay.createDiv();
correctLabel.style.fontWeight = "bold";
correctLabel.style.marginBottom = "4px";
@@ -3070,16 +3013,18 @@ var MCQModal = class extends import_obsidian8.Modal {
existingAnswer.correct = false;
existingAnswer.attempts += 1;
} else {
- this.session.answers.push({ questionIndex, selectedAnswerIndex: -1, correct: false, timeToAnswer: (Date.now() - this.questionStartTime) / 1e3, attempts: 3 });
+ this.session.answers.push({
+ questionIndex,
+ selectedAnswerIndex: -1,
+ correct: false,
+ timeToAnswer: (Date.now() - this.questionStartTime) / 1e3,
+ attempts: 3
+ });
}
- const continueBtn = correctAnswerDisplay.createEl("button", { text: "Continue to Next Question", cls: "mcq-continue-button" });
- continueBtn.style.marginTop = "10px";
- continueBtn.style.backgroundColor = "var(--interactive-accent)";
- continueBtn.style.color = "white";
- continueBtn.style.padding = "6px 12px";
- continueBtn.style.borderRadius = "4px";
- continueBtn.style.cursor = "pointer";
- continueBtn.style.border = "none";
+ const continueBtn = correctAnswerDisplay.createEl("button", {
+ text: "Continue to Next Question",
+ cls: "mcq-continue-button"
+ });
continueBtn.addEventListener("click", () => {
this.session.currentQuestionIndex++;
this.questionStartTime = Date.now();
@@ -3108,10 +3053,6 @@ var MCQModal = class extends import_obsidian8.Modal {
const textSpan = choiceBtn.createSpan("mcq-choice-text");
textSpan.setText(choice || "(Empty choice)");
const shortcutHint = choiceBtn.createSpan("mcq-shortcut-hint");
- shortcutHint.style.fontSize = "0.8em";
- shortcutHint.style.color = "var(--mcq-text-muted)";
- shortcutHint.style.marginLeft = "auto";
- shortcutHint.style.paddingLeft = "10px";
shortcutHint.setText(`${String.fromCharCode(65 + index)} or ${index + 1}`);
choiceBtn.addEventListener("click", () => this.handleAnswer(index));
});
@@ -3133,7 +3074,6 @@ var MCQModal = class extends import_obsidian8.Modal {
answer.timeToAnswer = timeToAnswer;
answer.attempts += 1;
if (answer.attempts >= 2 && !answer.correct) {
- console.log(`Question ${questionIndex + 1} has ${answer.attempts} attempts, marking as zero points`);
answer.selectedAnswerIndex = -1;
}
} else {
@@ -3176,7 +3116,7 @@ var MCQModal = class extends import_obsidian8.Modal {
this.session.completedAt = Date.now();
this.plugin.mcqService.saveMCQSession(this.session);
this.plugin.savePluginData();
- contentEl.createEl("h2").setText("Review Complete");
+ contentEl.createEl("h2", { text: "Review Complete" });
const scoreEl = contentEl.createDiv("mcq-score");
const scoreTextEl = scoreEl.createDiv("mcq-score-text");
const scorePercentage = this.session.score;
@@ -3226,14 +3166,11 @@ var MCQModal = class extends import_obsidian8.Modal {
if (ratingDetails) {
const detailsEl = scoreEl.createDiv("mcq-score-details");
detailsEl.setText(ratingDetails);
- detailsEl.style.fontSize = "0.9em";
- detailsEl.style.color = "var(--text-muted)";
- detailsEl.style.marginTop = "4px";
}
const resultsEl = contentEl.createDiv("mcq-results");
- resultsEl.createEl("h3").setText("Question Results");
+ resultsEl.createEl("h3", { text: "Question Results" });
if (this.session.answers.length === 0) {
- resultsEl.createDiv("mcq-no-answers").setText("No questions were answered in this session.");
+ resultsEl.createDiv({ cls: "mcq-no-answers", text: "No questions were answered in this session." });
} else {
this.session.answers.forEach((answer) => {
try {
@@ -3241,39 +3178,38 @@ var MCQModal = class extends import_obsidian8.Modal {
if (!question || !question.choices)
return;
const resultItem = resultsEl.createDiv("mcq-result-item");
- resultItem.createDiv("mcq-result-question").setText(question.question || "Question text missing");
+ resultItem.createDiv({ cls: "mcq-result-question", text: question.question || "Question text missing" });
if (answer.attempts > 1) {
if (answer.selectedAnswerIndex !== -1) {
const yourAnswer = resultItem.createDiv("mcq-result-your-answer");
- yourAnswer.createSpan("mcq-result-label").setText("Your final answer (correct after multiple attempts): ");
- yourAnswer.createSpan("mcq-result-correct").setText(question.choices[answer.selectedAnswerIndex] || "(invalid choice)");
+ yourAnswer.createSpan({ cls: "mcq-result-label", text: "Your final answer (correct after multiple attempts): " });
+ yourAnswer.createSpan({ cls: "mcq-result-correct", text: question.choices[answer.selectedAnswerIndex] || "(invalid choice)" });
} else {
const yourAnswer = resultItem.createDiv("mcq-result-your-answer");
- yourAnswer.createSpan("mcq-result-label").setText("Your answer: ");
- yourAnswer.createSpan("mcq-result-incorrect").setText('(Incorrect - used "Show Answer" option)');
+ yourAnswer.createSpan({ cls: "mcq-result-label", text: "Your answer: " });
+ yourAnswer.createSpan({ cls: "mcq-result-incorrect", text: '(Incorrect - used "Show Answer" option)' });
}
const correctAnswer = resultItem.createDiv("mcq-result-correct-answer");
- correctAnswer.createSpan("mcq-result-label").setText("Correct answer: ");
- correctAnswer.createSpan("mcq-result-correct").setText(question.choices[question.correctAnswerIndex] || "(invalid choice)");
+ correctAnswer.createSpan({ cls: "mcq-result-label", text: "Correct answer: " });
+ correctAnswer.createSpan({ cls: "mcq-result-correct", text: question.choices[question.correctAnswerIndex] || "(invalid choice)" });
} else {
const yourAnswer = resultItem.createDiv("mcq-result-your-answer");
- yourAnswer.createSpan("mcq-result-label").setText("Your answer: ");
- yourAnswer.createSpan(answer.correct ? "mcq-result-correct" : "mcq-result-incorrect").setText(question.choices[answer.selectedAnswerIndex] || "(invalid choice)");
+ yourAnswer.createSpan({ cls: "mcq-result-label", text: "Your answer: " });
+ yourAnswer.createSpan({ cls: answer.correct ? "mcq-result-correct" : "mcq-result-incorrect", text: question.choices[answer.selectedAnswerIndex] || "(invalid choice)" });
if (!answer.correct) {
const correctAnswer = resultItem.createDiv("mcq-result-correct-answer");
- correctAnswer.createSpan("mcq-result-label").setText("Correct answer: ");
- correctAnswer.createSpan("mcq-result-correct").setText(question.choices[question.correctAnswerIndex] || "(invalid choice)");
+ correctAnswer.createSpan({ cls: "mcq-result-label", text: "Correct answer: " });
+ correctAnswer.createSpan({ cls: "mcq-result-correct", text: question.choices[question.correctAnswerIndex] || "(invalid choice)" });
}
}
- resultItem.createDiv("mcq-result-attempts").setText(`Attempts: ${answer.attempts}`);
- resultItem.createDiv("mcq-result-time").setText(`Time: ${Math.round(answer.timeToAnswer)} seconds`);
+ resultItem.createDiv({ cls: "mcq-result-attempts", text: `Attempts: ${answer.attempts}` });
+ resultItem.createDiv({ cls: "mcq-result-time", text: `Time: ${Math.round(answer.timeToAnswer)} seconds` });
} catch (error) {
console.error("Error displaying answer result:", error);
}
});
}
- const closeBtn = contentEl.createEl("button", { cls: "mcq-close-btn" });
- closeBtn.setText("Close");
+ const closeBtn = contentEl.createEl("button", { cls: "mcq-close-btn", text: "Close" });
closeBtn.addEventListener("click", () => {
if (this.onCompleteCallback) {
this.onCompleteCallback(this.notePath, this.session.score, true);
@@ -3282,10 +3218,9 @@ var MCQModal = class extends import_obsidian8.Modal {
});
} catch (error) {
console.error("Error completing MCQ session:", error);
- contentEl.createEl("h2").setText("Error Completing Session");
- contentEl.createEl("p").setText("There was an error completing the MCQ session. Please try again.");
- const errorCloseBtn = contentEl.createEl("button", { cls: "mcq-close-btn" });
- errorCloseBtn.setText("Close");
+ contentEl.createEl("h2", { text: "Error Completing Session" });
+ contentEl.createEl("p", { text: "There was an error completing the MCQ session. Please try again." });
+ const errorCloseBtn = contentEl.createEl("button", { cls: "mcq-close-btn", text: "Close" });
errorCloseBtn.addEventListener("click", () => this.close());
}
}
@@ -3987,9 +3922,7 @@ var LinkAnalyzer = class {
*/
static findStartingNode(nodes) {
var _a, _b, _c, _d;
- console.log("LinkAnalyzer: Starting node selection process...");
if (Object.keys(nodes).length === 0) {
- console.log("LinkAnalyzer: No nodes found, returning empty array.");
return [];
}
const folderNodes = {};
@@ -4003,35 +3936,25 @@ var LinkAnalyzer = class {
for (const folderPath in folderNodes) {
const folderName = ((_a = folderPath.split("/").pop()) == null ? void 0 : _a.toLowerCase()) || "";
const filesInFolder = folderNodes[folderPath];
- console.log(`LinkAnalyzer: Checking for exact match with folder name "${folderName}" in folder "${folderPath}"...`);
for (const path of filesInFolder) {
- const fileName = ((_b = path.split("/").pop()) == null ? void 0 : _b.toLowerCase()) || "";
- const fileNameWithoutExt = fileName.replace(/\.md$/, "");
- if (fileNameWithoutExt === folderName) {
- console.log(`LinkAnalyzer: Selected main file with exact folder name match: ${path}`);
+ const fileName = ((_b = path.split("/").pop()) == null ? void 0 : _b.toLowerCase().replace(/\.md$/, "")) || "";
+ if (fileName === folderName) {
return [path];
}
}
- console.log(`LinkAnalyzer: Checking for partial match with folder name "${folderName}"...`);
for (const path of filesInFolder) {
- const fileName = ((_c = path.split("/").pop()) == null ? void 0 : _c.toLowerCase()) || "";
- const fileNameWithoutExt = fileName.replace(/\.md$/, "");
- if (fileNameWithoutExt.includes(folderName) || folderName.includes(fileNameWithoutExt)) {
- console.log(`LinkAnalyzer: Selected main file with partial folder name match: ${path}`);
+ const fileName = ((_c = path.split("/").pop()) == null ? void 0 : _c.toLowerCase().replace(/\.md$/, "")) || "";
+ if (fileName.includes(folderName) || folderName.includes(fileName)) {
return [path];
}
}
- console.log("LinkAnalyzer: Checking for common index or main file patterns...");
for (const path of filesInFolder) {
- const fileName = ((_d = path.split("/").pop()) == null ? void 0 : _d.toLowerCase()) || "";
- const fileNameWithoutExt = fileName.replace(/\.md$/, "");
- if (fileNameWithoutExt === "index" || fileNameWithoutExt === "main" || fileNameWithoutExt.includes("index") || fileNameWithoutExt.includes("readme") || fileNameWithoutExt.includes("main")) {
- console.log(`LinkAnalyzer: Selected main file by standard name pattern: ${path}`);
+ const fileName = ((_d = path.split("/").pop()) == null ? void 0 : _d.toLowerCase().replace(/\.md$/, "")) || "";
+ if (fileName === "index" || fileName === "main" || fileName.includes("index") || fileName.includes("readme") || fileName.includes("main")) {
return [path];
}
}
}
- console.log("LinkAnalyzer: Checking for files with the most outgoing links...");
const sortedNodes = Object.values(nodes).sort((a, b2) => {
const regularLinkDiff = b2.regularLinks.length - a.regularLinks.length;
if (regularLinkDiff !== 0) {
@@ -4040,10 +3963,8 @@ var LinkAnalyzer = class {
return b2.outgoingLinks.length - a.outgoingLinks.length;
});
if (sortedNodes.length > 0 && (sortedNodes[0].regularLinks.length > 0 || sortedNodes[0].outgoingLinks.length > 0)) {
- console.log(`LinkAnalyzer: Selected main file by link count: ${sortedNodes[0].path} with ${sortedNodes[0].regularLinks.length} regular links`);
return [sortedNodes[0].path];
}
- console.log(`LinkAnalyzer: No clear main file identified, using first file as root node`);
return Object.keys(nodes).length > 0 ? [Object.keys(nodes)[0]] : [];
}
/**
@@ -4072,10 +3993,8 @@ var LinkAnalyzer = class {
fileFolders.set(path, folderPath);
}
const mainFolder = fileFolders.get(startNodePath) || "";
- console.log(`LinkAnalyzer: Starting ordered traversal from: ${startNodePath} in main folder: ${mainFolder || "vault root"}`);
const traverse = (currentNodePath, currentDepth = 0, currentMainFolder) => {
if (visited.has(currentNodePath)) {
- console.log(`${" ".repeat(currentDepth)}LinkAnalyzer: Already visited: ${currentNodePath}`);
return;
}
const node = nodes[currentNodePath];
@@ -4083,26 +4002,21 @@ var LinkAnalyzer = class {
console.warn(`${" ".repeat(currentDepth)}LinkAnalyzer: Node not found for path: ${currentNodePath}`);
return;
}
- console.log(`${" ".repeat(currentDepth)}LinkAnalyzer: Traversing: ${currentNodePath}`);
visited.add(currentNodePath);
traversalOrder.push(currentNodePath);
const currentNodeFolder = fileFolders.get(currentNodePath) || "";
const linksToFollow = node.regularLinks.length > 0 ? node.regularLinks : node.outgoingLinks;
for (const linkedPath of linksToFollow) {
if (!nodes[linkedPath]) {
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Skipping unknown linked path: ${linkedPath}`);
continue;
}
const linkedNodeFolder = fileFolders.get(linkedPath) || "";
if (nodes[linkedPath] && linkedNodeFolder.startsWith(currentMainFolder)) {
if (!visited.has(linkedPath)) {
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Following link within main hierarchy to: ${linkedPath}`);
traverse(linkedPath, currentDepth + 1, currentMainFolder);
} else {
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Link to already visited node in main hierarchy: ${linkedPath}`);
}
} else {
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Ignoring link outside main hierarchy or unknown node: ${linkedPath} (from ${currentNodeFolder} to ${linkedNodeFolder})`);
}
}
};
@@ -4111,7 +4025,6 @@ var LinkAnalyzer = class {
} else {
console.warn(`LinkAnalyzer: Start node ${startNodePath} not found in nodes. Traversal order might be empty or incomplete.`);
}
- console.log(`LinkAnalyzer: Final traversal order from ${startNodePath} (in folder '${mainFolder || "vault root"}') has ${traversalOrder.length} files: ${traversalOrder.join(" -> ")}`);
return traversalOrder;
}
/**
@@ -4180,7 +4093,6 @@ var LinkAnalyzer = class {
seenLinks.add(resolvedPath);
}
}
- console.log(`LinkAnalyzer: Analyzed links in ${filePath}, found ${resolvedLinks.length} unique links in order`);
return resolvedLinks;
} catch (error) {
console.error(`LinkAnalyzer: Error analyzing links in ${filePath}:`, error);
@@ -4285,7 +4197,6 @@ var ContextMenuHandler = class {
this.plugin.registerEvent(
this.plugin.app.workspace.on("file-menu", this.handleFileMenuEvent.bind(this))
);
- console.log("Unified context menu handler registered for 'file-menu'.");
}
/**
* Handles the 'file-menu' event for TAbstractFile (could be TFile or TFolder).
@@ -4295,10 +4206,8 @@ var ContextMenuHandler = class {
*/
handleFileMenuEvent(menu, abstractFile) {
if (abstractFile instanceof import_obsidian11.TFolder) {
- console.log("Folder right-clicked:", abstractFile.path);
this.addFolderMenuItems(menu, abstractFile);
} else if (abstractFile instanceof import_obsidian11.TFile && abstractFile.extension === "md") {
- console.log("Markdown file right-clicked:", abstractFile.path);
this.addFileMenuItems(menu, abstractFile);
}
}
@@ -4350,15 +4259,12 @@ var ContextMenuHandler = class {
* @param folder Target folder
*/
addFolderMenuItems(menu, folder) {
- console.log("Adding menu items for folder:", folder.path);
try {
menu.addItem((item) => {
item.setTitle("Add folder to review").setIcon("calendar-plus").onClick(() => {
- console.log("Context menu: Adding folder to review:", folder.path);
this.addFolderToReview(folder);
});
});
- console.log("Menu items added successfully for folder:", folder.path);
} catch (error) {
console.error("Error adding folder menu items:", error);
}
@@ -4369,7 +4275,6 @@ var ContextMenuHandler = class {
* @param folder Target folder
*/
async addFolderToReview(folder) {
- console.log("Processing folder:", folder.path);
new import_obsidian11.Notice(`Analyzing folder structure for "${folder.name}"...`);
try {
const allFiles = this.plugin.app.vault.getMarkdownFiles().filter((file) => {
@@ -4392,7 +4297,6 @@ var ContextMenuHandler = class {
const folderName = folder.name.toLowerCase();
if (fileName === folderName) {
mainFilePath = file.path;
- console.log(`Found main file with exact folder name match: ${mainFilePath}`);
break;
}
}
@@ -4402,7 +4306,6 @@ var ContextMenuHandler = class {
const folderName = folder.name.toLowerCase();
if (fileName.includes(folderName) || folderName.includes(fileName) || fileName === "index" || fileName === "main" || fileName.includes("index") || fileName.includes("main")) {
mainFilePath = file.path;
- console.log(`Found main file by partial name match: ${mainFilePath}`);
break;
}
}
@@ -4411,7 +4314,6 @@ var ContextMenuHandler = class {
const activeFile = this.plugin.app.workspace.getActiveFile();
if (activeFile && activeFile.extension === "md" && allFiles.some((f) => f.path === activeFile.path)) {
mainFilePath = activeFile.path;
- console.log(`Using active note as main file: ${mainFilePath}`);
}
}
let traversalOrder = [];
@@ -4443,17 +4345,14 @@ var ContextMenuHandler = class {
}
};
if (mainFilePath) {
- console.log(`Starting traversal from identified main file: ${mainFilePath}`);
await processLinksRecursively(mainFilePath);
}
const sortedAllFiles = [...allFiles].sort((a, b2) => a.path.localeCompare(b2.path));
for (const file of sortedAllFiles) {
if (!visited.has(file.path)) {
- console.log(`Processing new branch or unlinked file: ${file.path}`);
await processLinksRecursively(file.path);
}
}
- console.log(`Final traversal order determined with ${traversalOrder.length} files.`);
const count = await this.plugin.reviewScheduleService.scheduleNotesInOrder(traversalOrder);
if (count > 0) {
await this.plugin.savePluginData();
@@ -5062,11 +4961,9 @@ var NoteItemRenderer = class {
if (note.scheduleCategory === "initial") {
const totalInitialSteps = this.plugin.settings.initialScheduleCustomIntervals.length;
const currentStepDisplay = note.reviewCount < totalInitialSteps ? note.reviewCount + 1 : totalInitialSteps;
- phaseEl.innerHTML = `
-
Initial
- ${currentStepDisplay}/${totalInitialSteps}
- ${formattedTime}
- `;
+ phaseEl.createDiv({ title: "Initial", text: "Initial" });
+ phaseEl.createDiv({ title: `${currentStepDisplay}/${totalInitialSteps}`, text: `${currentStepDisplay}/${totalInitialSteps}` });
+ const phaseTimeEl = phaseEl.createDiv({ cls: "phase-time", title: formattedTime, text: formattedTime });
phaseEl.addClass("review-phase-initial");
} else {
phaseEl.setText(note.scheduleCategory === "graduated" ? "Graduated" : "Spaced");
@@ -6204,6 +6101,8 @@ var ReviewSidebarView = class extends import_obsidian16.ItemView {
this.lastSelectedNotePath = null;
this.lastScrollPosition = 0;
this.expandedUpcomingDayKey = null;
+ // State for upcoming section
+ this.resizeObserver = null;
this.listViewRenderer = null;
// Persistent UI elements
this.mainContainer = null;
@@ -6238,7 +6137,7 @@ var ReviewSidebarView = class extends import_obsidian16.ItemView {
this.plugin.events.off("sidebar-update", this.refresh.bind(this));
}
ensureBaseStructure() {
- const contentEl = this.containerEl || this.contentEl;
+ const contentEl = this.containerEl;
if (!contentEl)
return;
if (!this.mainContainer) {
@@ -6503,7 +6402,7 @@ var ReviewSidebarView = class extends import_obsidian16.ItemView {
sidebarViewType: this.plugin.settings.sidebarViewType
};
}
- async setViewState(state, e) {
+ async setViewState(state) {
var _a, _b, _c;
if (!state)
return;
@@ -7006,7 +6905,6 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
openRouterModel: this.plugin.settings.openRouterModel
};
window.localStorage.setItem("spaceforge-api-settings", JSON.stringify(apiSettings));
- console.log("Updated API settings backup with MCQ state");
} catch (e) {
console.error("Error updating API settings backup:", e);
}
@@ -7030,7 +6928,7 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
this.plugin.settings.openRouterApiKey = value;
await this.plugin.savePluginData();
}));
- apiKeyContainer.createEl("div", { text: "Get your API key at https://openrouter.ai/keys" });
+ apiKeyContainer.createEl("div").setText("Get your API key at https://openrouter.ai/keys");
new import_obsidian17.Setting(mcqSection).setName("OpenRouter Model").setDesc("Model identifier from OpenRouter (e.g., openai/gpt-4.1-mini)").addText((text) => text.setPlaceholder("Enter OpenRouter model identifier").setValue(this.plugin.settings.openRouterModel).onChange(async (value) => {
this.plugin.settings.openRouterModel = value;
await this.plugin.savePluginData();
@@ -7120,7 +7018,7 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
await this.plugin.savePluginData();
}));
const difficultyContainer = mcqFormattingGrid.createEl("div");
- new import_obsidian17.Setting(difficultyContainer).setName("MCQ difficulty").setDesc("Complexity level").addDropdown((dropdown) => dropdown.addOption("basic", "Basic recall").addOption("advanced", "Advanced understanding").setValue(this.plugin.settings.mcqDifficulty).onChange(async (value) => {
+ new import_obsidian17.Setting(difficultyContainer).setName("MCQ difficulty").setDesc("Complexity level").addDropdown((dropdown) => dropdown.addOption("basic" /* Basic */, "Basic recall").addOption("advanced" /* Advanced */, "Advanced understanding").setValue(this.plugin.settings.mcqDifficulty).onChange(async (value) => {
this.plugin.settings.mcqDifficulty = value;
await this.plugin.savePluginData();
}));
@@ -7259,15 +7157,28 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
sm2List.createEl("li", { text: "Postponed items: Explicitly moved to tomorrow with a one-step quality penalty." });
sm2List.createEl("li", { text: "Both cases reset the repetition count to 1 and update the ease factor." });
const ratingsTable = container.createEl("table", { cls: "sf-ratings-table" });
- ratingsTable.innerHTML = `
- | Rating (0-5) | Description | Effect on Interval |
-
- | 0-2 | Incorrect / struggled | Resets, shortest interval |
- | 3 | Correct with difficulty | Small increase |
- | 4 | Correct with hesitation | Moderate increase |
- | 5 | Perfect recall | Largest increase |
-
- `;
+ const thead = ratingsTable.createTHead();
+ const tbody = ratingsTable.createTBody();
+ const headerRow = thead.insertRow();
+ headerRow.createEl("th", { text: "Rating (0-5)" });
+ headerRow.createEl("th", { text: "Description" });
+ headerRow.createEl("th", { text: "Effect on Interval" });
+ const row1 = tbody.insertRow();
+ row1.createEl("td", { text: "0-2" });
+ row1.createEl("td", { text: "Incorrect / struggled" });
+ row1.createEl("td", { text: "Resets, shortest interval" });
+ const row2 = tbody.insertRow();
+ row2.createEl("td", { text: "3" });
+ row2.createEl("td", { text: "Correct with difficulty" });
+ row2.createEl("td", { text: "Small increase" });
+ const row3 = tbody.insertRow();
+ row3.createEl("td", { text: "4" });
+ row3.createEl("td", { text: "Correct with hesitation" });
+ row3.createEl("td", { text: "Moderate increase" });
+ const row4 = tbody.insertRow();
+ row4.createEl("td", { text: "5" });
+ row4.createEl("td", { text: "Perfect recall" });
+ row4.createEl("td", { text: "Largest increase" });
} else if (algorithm === "fsrs") {
container.createEl("h4", { text: "About the FSRS Algorithm" });
container.createEl("p", {
@@ -7282,15 +7193,28 @@ var SpaceforgeSettingTab = class extends import_obsidian17.PluginSettingTab {
fsrsList.createEl("li", { text: "Retention: The probability of recalling a card at the time of review." });
fsrsList.createEl("li", { text: "Learning Steps: Initial short intervals for new cards (configurable)." });
const ratingsTable = container.createEl("table", { cls: "sf-ratings-table" });
- ratingsTable.innerHTML = `
- | Rating (1-4) | Description | Effect on Stability/Difficulty |
-
- | 1 (Again) | Forgot the card | Decreases stability, may increase difficulty |
- | 2 (Hard) | Recalled with significant difficulty | Smaller increase in stability |
- | 3 (Good) | Recalled correctly | Standard increase in stability |
- | 4 (Easy) | Recalled very easily | Largest increase in stability, may decrease difficulty |
-
- `;
+ const thead = ratingsTable.createTHead();
+ const tbody = ratingsTable.createTBody();
+ const headerRow = thead.insertRow();
+ headerRow.createEl("th", { text: "Rating (1-4)" });
+ headerRow.createEl("th", { text: "Description" });
+ headerRow.createEl("th", { text: "Effect on Stability/Difficulty" });
+ const row1 = tbody.insertRow();
+ row1.createEl("td", { text: "1 (Again)" });
+ row1.createEl("td", { text: "Forgot the card" });
+ row1.createEl("td", { text: "Decreases stability, may increase difficulty" });
+ const row2 = tbody.insertRow();
+ row2.createEl("td", { text: "2 (Hard)" });
+ row2.createEl("td", { text: "Recalled with significant difficulty" });
+ row2.createEl("td", { text: "Smaller increase in stability" });
+ const row3 = tbody.insertRow();
+ row3.createEl("td", { text: "3 (Good)" });
+ row3.createEl("td", { text: "Recalled correctly" });
+ row3.createEl("td", { text: "Standard increase in stability" });
+ const row4 = tbody.insertRow();
+ row4.createEl("td", { text: "4 (Easy)" });
+ row4.createEl("td", { text: "Recalled very easily" });
+ row4.createEl("td", { text: "Largest increase in stability, may decrease difficulty" });
container.createEl("p", { text: "FSRS parameters (weights, retention, etc.) can be tuned, but the defaults are generally effective." });
}
}
@@ -7405,7 +7329,8 @@ ${noteContent}`;
try {
console.log(`Making API request to OpenRouter using model: ${model} with difficulty: ${difficulty}`);
const systemPrompt = difficulty === "basic" ? settings.mcqBasicSystemPrompt : settings.mcqAdvancedSystemPrompt;
- const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
+ const response = await (0, import_obsidian18.requestUrl)({
+ url: "https://openrouter.ai/api/v1/chat/completions",
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -7429,12 +7354,11 @@ ${noteContent}`;
]
})
});
- if (!response.ok) {
- const errorText = await response.text();
- console.error("OpenRouter API error:", errorText);
- throw new Error(`API request failed (${response.status}): ${errorText}`);
+ if (response.status !== 200) {
+ console.error("OpenRouter API error:", response.text);
+ throw new Error(`API request failed (${response.status}): ${response.text}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.choices || !data.choices.length || !data.choices[0].message) {
console.error("Invalid API response format from OpenRouter:", data);
throw new Error("Invalid API response format from OpenRouter - missing choices");
@@ -7618,7 +7542,8 @@ ${noteContent}`;
const systemPrompt = difficulty === "basic" ? settings.mcqBasicSystemPrompt : settings.mcqAdvancedSystemPrompt;
console.log(`Making API request to OpenAI using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch("https://api.openai.com/v1/chat/completions", {
+ const response = await (0, import_obsidian19.requestUrl)({
+ url: "https://api.openai.com/v1/chat/completions",
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -7632,12 +7557,12 @@ ${noteContent}`;
]
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json || { message: response.text };
console.error("OpenAI API error:", response.status, errorData);
throw new Error(`API request failed (${response.status}): ${((_a = errorData.error) == null ? void 0 : _a.message) || errorData.message || "Unknown error"}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.choices || !data.choices.length || !data.choices[0].message || !data.choices[0].message.content) {
console.error("Invalid API response format from OpenAI:", data);
throw new Error("Invalid API response format from OpenAI - missing content");
@@ -7794,8 +7719,8 @@ ${noteContent}`;
const systemPrompt = difficulty === "basic" ? settings.mcqBasicSystemPrompt : settings.mcqAdvancedSystemPrompt;
console.log(`Making API request to Ollama at ${apiUrl} using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch(`${apiUrl}/api/chat`, {
- // Common Ollama chat endpoint
+ const response = await (0, import_obsidian20.requestUrl)({
+ url: `${apiUrl}/api/chat`,
method: "POST",
headers: {
"Content-Type": "application/json"
@@ -7810,12 +7735,12 @@ ${noteContent}`;
// Ensure we get the full response, not a stream
})
});
- if (!response.ok) {
- const errorText = await response.text();
+ if (response.status !== 200) {
+ const errorText = response.text;
console.error("Ollama API error:", response.status, errorText);
throw new Error(`API request failed (${response.status}): ${errorText}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.message || !data.message.content) {
console.error("Invalid API response format from Ollama:", data);
throw new Error("Invalid API response format from Ollama - missing message content");
@@ -7968,7 +7893,8 @@ ${noteContent}`;
console.log(`Making API request to Gemini using model: ${model}`);
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
try {
- const response = await fetch(apiUrl, {
+ const response = await (0, import_obsidian21.requestUrl)({
+ url: apiUrl,
method: "POST",
headers: {
"Content-Type": "application/json"
@@ -7983,13 +7909,13 @@ ${noteContent}`;
// }
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json;
console.error("Gemini API error:", response.status, errorData);
const errorMessage = ((_a = errorData == null ? void 0 : errorData.error) == null ? void 0 : _a.message) || (errorData == null ? void 0 : errorData.message) || "Unknown error";
throw new Error(`API request failed (${response.status}): ${errorMessage}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.candidates || !data.candidates.length || !data.candidates[0].content || !data.candidates[0].content.parts || !data.candidates[0].content.parts.length || !data.candidates[0].content.parts[0].text) {
console.error("Invalid API response format from Gemini:", data);
throw new Error("Invalid API response format from Gemini - missing content");
@@ -8147,7 +8073,8 @@ ${noteContent}`;
const systemPrompt = difficulty === "basic" ? settings.mcqBasicSystemPrompt : settings.mcqAdvancedSystemPrompt;
console.log(`Making API request to Claude using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch("https://api.anthropic.com/v1/messages", {
+ const response = await (0, import_obsidian22.requestUrl)({
+ url: "https://api.anthropic.com/v1/messages",
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -8164,12 +8091,12 @@ ${noteContent}`;
]
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json || { message: response.text };
console.error("Claude API error:", response.status, errorData);
throw new Error(`API request failed (${response.status}): ${((_a = errorData.error) == null ? void 0 : _a.message) || errorData.message || "Unknown error"}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.content || !data.content.length || !data.content[0].text) {
console.error("Invalid API response format from Claude:", data);
throw new Error("Invalid API response format from Claude - missing content");
@@ -8353,7 +8280,8 @@ ${noteContent}`;
const systemPrompt = difficulty === "basic" ? settings.mcqBasicSystemPrompt : settings.mcqAdvancedSystemPrompt;
console.log(`Making API request to Together AI using model: ${model} with difficulty: ${difficulty}`);
try {
- const response = await fetch("https://api.together.xyz/v1/chat/completions", {
+ const response = await (0, import_obsidian23.requestUrl)({
+ url: "https://api.together.xyz/v1/chat/completions",
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -8369,12 +8297,12 @@ ${noteContent}`;
]
})
});
- if (!response.ok) {
- const errorData = await response.json().catch(() => ({ message: response.statusText }));
+ if (response.status !== 200) {
+ const errorData = response.json || { message: response.text };
console.error("Together AI API error:", response.status, errorData);
throw new Error(`API request failed (${response.status}): ${((_a = errorData.error) == null ? void 0 : _a.message) || errorData.message || "Unknown error"}`);
}
- const data = await response.json();
+ const data = response.json;
if (!data.choices || !data.choices.length || !data.choices[0].message || !data.choices[0].message.content) {
console.error("Invalid API response format from Together AI:", data);
throw new Error("Invalid API response format from Together AI - missing content");
@@ -8921,14 +8849,7 @@ var ReviewScheduleService = class {
*/
calculateSM2Schedule(currentInterval, currentEase, qualityRating, repetitionCount = 0, daysLate = 0, isSkipped = false) {
if (isSkipped || daysLate > 0) {
- console.log(`[Modified SM-2] Processing ${isSkipped ? "skipped" : "overdue"} item:
- - Days late: ${daysLate}
- - Original quality: ${qualityRating}
- - Current interval: ${currentInterval}
- - Current ease: ${currentEase / 100}`);
const q_eff = isSkipped ? Math.max(0, qualityRating - 1) : 0;
- console.log(`[Modified SM-2] Applied penalty:
- - Effective quality: ${q_eff}`);
let ease2 = currentEase / 100;
ease2 = ease2 + (0.1 - (5 - q_eff) * (0.08 + (5 - q_eff) * 0.02));
ease2 = Math.max(1.3, ease2);
@@ -8940,10 +8861,6 @@ var ReviewScheduleService = class {
repetitionCount: 1
// Reset repetition count to 1
};
- console.log(`[Modified SM-2] Result for ${isSkipped ? "skipped" : "overdue"} item:
- - New interval: ${result.interval} day(s)
- - New ease: ${result.ease / 100}
- - New repetition count: ${result.repetitionCount}`);
return result;
}
let ease = currentEase / 100;
@@ -9031,7 +8948,6 @@ var ReviewScheduleService = class {
const schedule = this.schedules[path];
if (!schedule)
return;
- console.log(`Skipping note ${path} with algorithm ${schedule.schedulingAlgorithm}`);
const effectiveReviewDate = currentReviewDate || Date.now();
const reviewDateObj = new Date(effectiveReviewDate);
if (schedule.schedulingAlgorithm === "fsrs") {
@@ -9120,7 +9036,6 @@ var ReviewScheduleService = class {
async advanceNote(path) {
const schedule = this.schedules[path];
if (!schedule) {
- console.warn(`[ReviewScheduleService] Advance: Schedule not found for path ${path}`);
return false;
}
const todayUTCMidnight = DateUtils.startOfUTCDay(/* @__PURE__ */ new Date());
@@ -9184,7 +9099,6 @@ var ReviewScheduleService = class {
const content = await this.plugin.app.vault.read(file);
return EstimationUtils.estimateReviewTime(file, content);
} catch (error) {
- console.error("Error estimating review time:", error);
return 60;
}
}
@@ -9268,7 +9182,6 @@ var ReviewScheduleService = class {
async updateCustomNoteOrder(order) {
const uniqueValidPaths = Array.from(new Set(order)).filter((path) => this.schedules[path] !== void 0);
this.customNoteOrder = uniqueValidPaths;
- console.log(`Updated custom note order with ${this.customNoteOrder.length} unique entries`);
if (this.plugin.events) {
this.plugin.events.emit("sidebar-update");
}
@@ -9326,7 +9239,6 @@ var ReviewScheduleService = class {
this.customNoteOrder.push(newPath);
}
}
- console.log(`Handled rename from ${oldPath} to ${newPath}. Schedule updated.`);
if (this.plugin.events) {
this.plugin.events.emit("sidebar-update");
}
@@ -9359,7 +9271,6 @@ var ReviewScheduleService = class {
}
}
}
- console.log(`Converted ${convertedCount} SM-2 cards to FSRS.`);
if (this.plugin.events) {
this.plugin.events.emit("sidebar-update");
}
@@ -9389,7 +9300,6 @@ var ReviewScheduleService = class {
}
}
}
- console.log(`Converted ${convertedCount} FSRS cards to SM-2.`);
if (this.plugin.events) {
this.plugin.events.emit("sidebar-update");
}
@@ -9642,11 +9552,9 @@ var MCQService = class {
this.mcqSets = {};
return null;
}
- const sets = Object.values(this.mcqSets).filter((set) => set && set.notePath === notePath).sort((a, b2) => b2.generatedAt - a.generatedAt);
- if (sets.length > 0 && sets[0].questions && sets[0].questions.length > 0) {
+ const sets = Object.values(this.mcqSets).filter((set) => set && set.notePath === notePath && set.questions && set.questions.length > 0).sort((a, b2) => b2.generatedAt - a.generatedAt);
+ if (sets.length > 0) {
return sets[0];
- } else if (sets.length > 0) {
- console.warn("Found MCQ set but it contains no valid questions:", sets[0]);
}
return null;
} catch (error) {
@@ -9717,9 +9625,7 @@ var MCQService = class {
if (mcqSet) {
mcqSet.needsQuestionRegeneration = true;
this.saveMCQSet(mcqSet);
- console.log(`MCQSet for ${notePath} flagged for regeneration.`);
} else {
- console.log(`No MCQSet found for ${notePath} to flag for regeneration.`);
}
}
};
@@ -9941,7 +9847,6 @@ var PomodoroService = class {
const remainingMs = this.state.pomodoroEndTimeMs - now;
this.state.pomodoroTimeLeftInSeconds = Math.max(0, Math.round(remainingMs / 1e3));
if (remainingMs <= 0) {
- console.log("Pomodoro timer ended while inactive. Handling potential transition.");
this.handleTimerEnd(true);
}
} else if (!this.state.pomodoroIsRunning) {
@@ -10024,11 +9929,11 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
this.addCommand({
id: "add-selected-file-to-review",
name: "Add Selected File to Review Schedule (File Explorer)",
- hotkeys: [{ modifiers: ["Alt", "Shift"], key: "s" }],
callback: () => {
const fileExplorerLeaf = this.app.workspace.getLeavesOfType("file-explorer")[0];
- if (fileExplorerLeaf && fileExplorerLeaf.view && fileExplorerLeaf.view.file) {
- const selectedFile = fileExplorerLeaf.view.file;
+ const viewWithFile = fileExplorerLeaf == null ? void 0 : fileExplorerLeaf.view;
+ if (viewWithFile == null ? void 0 : viewWithFile.file) {
+ const selectedFile = viewWithFile.file;
if (selectedFile instanceof import_obsidian26.TFile && selectedFile.extension === "md") {
this.reviewScheduleService.scheduleNoteForReview(selectedFile.path).then(() => this.savePluginData());
new import_obsidian26.Notice(`Added "${selectedFile.path}" to review schedule.`);
@@ -10136,7 +10041,10 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
styleEl.remove();
let existingData = {};
try {
- existingData = await this.loadData() || {};
+ const loaded = await this.loadData();
+ if (loaded) {
+ existingData = loaded;
+ }
} catch (loadError) {
console.warn("Could not load existing data during unload:", loadError);
}
@@ -10164,7 +10072,6 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
}
if (this.pomodoroService)
this.pomodoroService.destroy();
- this.app.workspace.detachLeavesOfType("spaceforge-review-schedule");
}
// private async _getEffectiveDataPathFromLocalStorage(): Promise {
// const customPath = await this.app.loadLocalStorage('spaceforgeCustomDataPath');
@@ -10389,7 +10296,6 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
this.addCommand({
id: "spaceforge-next-review-note",
name: "Next Review Note",
- hotkeys: [{ modifiers: ["Alt", "Shift"], key: "/" }],
callback: () => {
this.navigationController.navigateToNextNote();
}
@@ -10397,7 +10303,6 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
this.addCommand({
id: "spaceforge-previous-review-note",
name: "Previous Review Note",
- hotkeys: [{ modifiers: ["Alt", "Shift"], key: "." }],
callback: () => {
this.navigationController.navigateToPreviousNote();
}
@@ -10405,7 +10310,6 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
this.addCommand({
id: "spaceforge-review-current-note",
name: "Review Current Note",
- hotkeys: [{ modifiers: ["Alt", "Shift"], key: "," }],
callback: () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile instanceof import_obsidian26.TFile && activeFile.extension === "md") {
@@ -10418,7 +10322,6 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
this.addCommand({
id: "spaceforge-add-current-note-to-review",
name: "Add Current Note to Review Schedule",
- hotkeys: [{ modifiers: ["Alt", "Shift"], key: "\\\\" }],
callback: () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile instanceof import_obsidian26.TFile && activeFile.extension === "md") {
@@ -10432,7 +10335,6 @@ var SpaceforgePlugin = class extends import_obsidian26.Plugin {
this.addCommand({
id: "spaceforge-add-current-folder-to-review",
name: "Add Current Note's Folder to Review Schedule",
- hotkeys: [{ modifiers: ["Alt", "Shift"], key: "'" }],
callback: async () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile.parent && activeFile.parent instanceof import_obsidian26.TFolder) {
diff --git a/main.ts b/main.ts
index a4b2146..b75a35e 100644
--- a/main.ts
+++ b/main.ts
@@ -120,11 +120,11 @@ export default class SpaceforgePlugin extends Plugin {
this.addCommand({
id: 'add-selected-file-to-review',
name: 'Add Selected File to Review Schedule (File Explorer)',
- hotkeys: [{ modifiers: ['Alt', 'Shift'], key: 's' }],
callback: () => {
const fileExplorerLeaf = this.app.workspace.getLeavesOfType('file-explorer')[0];
- if (fileExplorerLeaf && fileExplorerLeaf.view && (fileExplorerLeaf.view as any).file) {
- const selectedFile = (fileExplorerLeaf.view as any).file;
+ const viewWithFile = fileExplorerLeaf?.view as { file?: TFile };
+ if (viewWithFile?.file) {
+ const selectedFile = viewWithFile.file;
if (selectedFile instanceof TFile && selectedFile.extension === 'md') {
this.reviewScheduleService.scheduleNoteForReview(selectedFile.path)
.then(() => this.savePluginData());
@@ -233,8 +233,13 @@ export default class SpaceforgePlugin extends Plugin {
const styleEl = document.getElementById(this.stylesheetId);
if (styleEl) styleEl.remove();
- let existingData = {};
- try { existingData = await this.loadData() || {}; }
+ let existingData: Partial = {};
+ try {
+ const loaded = await this.loadData();
+ if (loaded) {
+ existingData = loaded;
+ }
+ }
catch (loadError) { console.warn("Could not load existing data during unload:", loadError); }
try {
@@ -258,7 +263,6 @@ export default class SpaceforgePlugin extends Plugin {
} catch (error) { console.error('Error saving plugin data before unload:', error); }
if (this.pomodoroService) this.pomodoroService.destroy();
- this.app.workspace.detachLeavesOfType('spaceforge-review-schedule');
}
// private async _getEffectiveDataPathFromLocalStorage(): Promise {
@@ -364,8 +368,8 @@ export default class SpaceforgePlugin extends Plugin {
this.pluginState = { ...DEFAULT_APP_DATA.pluginState };
if (rawLoadedData?.pluginState) {
this.pluginState = { ...this.pluginState, ...rawLoadedData.pluginState };
- } else if (rawLoadedData && !rawLoadedData.pluginState && (rawLoadedData as any).schedules) { // Legacy check
- this.pluginState = { ...this.pluginState, ...(rawLoadedData as any) };
+ } else if (rawLoadedData && !rawLoadedData.pluginState && (rawLoadedData as Partial).schedules) { // Legacy check
+ this.pluginState = { ...this.pluginState, ...(rawLoadedData as Partial) };
}
// Ensure pomodoro state is initialized if not present in loaded data
@@ -548,7 +552,6 @@ export default class SpaceforgePlugin extends Plugin {
this.addCommand({
id: 'spaceforge-next-review-note',
name: 'Next Review Note',
- hotkeys: [{ modifiers: ['Alt', 'Shift'], key: '/' }],
callback: () => {
this.navigationController.navigateToNextNote();
},
@@ -557,7 +560,6 @@ export default class SpaceforgePlugin extends Plugin {
this.addCommand({
id: 'spaceforge-previous-review-note',
name: 'Previous Review Note',
- hotkeys: [{ modifiers: ['Alt', 'Shift'], key: '.' }],
callback: () => {
this.navigationController.navigateToPreviousNote();
},
@@ -566,7 +568,6 @@ export default class SpaceforgePlugin extends Plugin {
this.addCommand({
id: 'spaceforge-review-current-note',
name: 'Review Current Note',
- hotkeys: [{ modifiers: ['Alt', 'Shift'], key: ',' }],
callback: () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile instanceof TFile && activeFile.extension === 'md') {
@@ -580,7 +581,6 @@ export default class SpaceforgePlugin extends Plugin {
this.addCommand({
id: 'spaceforge-add-current-note-to-review',
name: 'Add Current Note to Review Schedule',
- hotkeys: [{ modifiers: ['Alt', 'Shift'], key: '\\\\' }],
callback: () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile instanceof TFile && activeFile.extension === 'md') {
@@ -596,7 +596,6 @@ export default class SpaceforgePlugin extends Plugin {
this.addCommand({
id: 'spaceforge-add-current-folder-to-review',
name: "Add Current Note's Folder to Review Schedule",
- hotkeys: [{ modifiers: ['Alt', 'Shift'], key: "'" }],
callback: async () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile.parent && activeFile.parent instanceof TFolder) {
diff --git a/services/mcq-service.ts b/services/mcq-service.ts
index e8cf84b..93261cd 100644
--- a/services/mcq-service.ts
+++ b/services/mcq-service.ts
@@ -61,14 +61,12 @@ export class MCQService {
// Find the latest MCQ set for this note
const sets = Object.values(this.mcqSets)
- .filter(set => set && set.notePath === notePath)
+ .filter(set => set && set.notePath === notePath && set.questions && set.questions.length > 0)
.sort((a, b) => b.generatedAt - a.generatedAt);
// Verify the set is valid before returning
- if (sets.length > 0 && sets[0].questions && sets[0].questions.length > 0) {
+ if (sets.length > 0) {
return sets[0];
- } else if (sets.length > 0) {
- console.warn('Found MCQ set but it contains no valid questions:', sets[0]);
}
return null;
@@ -157,9 +155,7 @@ export class MCQService {
if (mcqSet) {
mcqSet.needsQuestionRegeneration = true;
this.saveMCQSet(mcqSet); // Updates the in-memory reference; persistence handled by caller
- console.log(`MCQSet for ${notePath} flagged for regeneration.`);
} else {
- console.log(`No MCQSet found for ${notePath} to flag for regeneration.`);
}
}
}
diff --git a/services/pomodoro-service.ts b/services/pomodoro-service.ts
index 2b165ea..dcebaf9 100644
--- a/services/pomodoro-service.ts
+++ b/services/pomodoro-service.ts
@@ -280,7 +280,6 @@ export class PomodoroService {
// Timer should have ended while plugin was inactive/closed
// We could try to simulate the transition, but it gets complex.
// Simplest: Stop the timer, reset to the expected next state's duration.
- console.log("Pomodoro timer ended while inactive. Handling potential transition.");
this.handleTimerEnd(true); // Treat as skipped to avoid sound, force transition logic
}
} else if (!this.state.pomodoroIsRunning) {
diff --git a/services/review-schedule-service.ts b/services/review-schedule-service.ts
index b862990..4115f09 100644
--- a/services/review-schedule-service.ts
+++ b/services/review-schedule-service.ts
@@ -489,22 +489,12 @@ export class ReviewScheduleService {
// Handle overdue or skipped items according to modified SM-2 algorithm
if (isSkipped || daysLate > 0) {
- // Debug log
- console.log(`[Modified SM-2] Processing ${isSkipped ? 'skipped' : 'overdue'} item:
- - Days late: ${daysLate}
- - Original quality: ${qualityRating}
- - Current interval: ${currentInterval}
- - Current ease: ${currentEase/100}`);
-
// Determine effective quality rating:
// - If explicitly skipped, reduce quality by 1 (but not below 0)
// - If overdue, set quality to 0
// - If both overdue and explicitly skipped, prioritize the skip logic (user choice)
const q_eff = isSkipped ? Math.max(0, qualityRating - 1) : 0;
- console.log(`[Modified SM-2] Applied penalty:
- - Effective quality: ${q_eff}`);
-
// Convert ease from internal format (250 = 2.5) to SM-2 format (2.5)
let ease = currentEase / 100;
@@ -522,11 +512,6 @@ export class ReviewScheduleService {
repetitionCount: 1 // Reset repetition count to 1
};
- console.log(`[Modified SM-2] Result for ${isSkipped ? 'skipped' : 'overdue'} item:
- - New interval: ${result.interval} day(s)
- - New ease: ${result.ease/100}
- - New repetition count: ${result.repetitionCount}`);
-
return result;
}
@@ -656,7 +641,6 @@ export class ReviewScheduleService {
const schedule = this.schedules[path];
if (!schedule) return;
- console.log(`Skipping note ${path} with algorithm ${schedule.schedulingAlgorithm}`);
const effectiveReviewDate = currentReviewDate || Date.now();
const reviewDateObj = new Date(effectiveReviewDate);
@@ -755,7 +739,6 @@ export class ReviewScheduleService {
async advanceNote(path: string): Promise {
const schedule = this.schedules[path];
if (!schedule) {
- console.warn(`[ReviewScheduleService] Advance: Schedule not found for path ${path}`);
return false;
}
@@ -854,7 +837,6 @@ export class ReviewScheduleService {
const content = await this.plugin.app.vault.read(file);
return EstimationUtils.estimateReviewTime(file, content);
} catch (error) {
- console.error("Error estimating review time:", error);
return 60; // Default 1 minute
}
}
@@ -938,7 +920,6 @@ export class ReviewScheduleService {
// Filter out duplicate paths and ensure we only store paths that exist in our schedules
const uniqueValidPaths = Array.from(new Set(order)).filter(path => this.schedules[path] !== undefined);
this.customNoteOrder = uniqueValidPaths;
- console.log(`Updated custom note order with ${this.customNoteOrder.length} unique entries`);
// Data saving is now handled by main.ts after this method returns
@@ -1021,7 +1002,6 @@ export class ReviewScheduleService {
}
}
- console.log(`Handled rename from ${oldPath} to ${newPath}. Schedule updated.`);
// Notify any listeners (for UI updates)
// Data saving will be handled by the caller in main.ts
@@ -1062,7 +1042,6 @@ export class ReviewScheduleService {
}
}
}
- console.log(`Converted ${convertedCount} SM-2 cards to FSRS.`);
if (this.plugin.events) {
this.plugin.events.emit('sidebar-update'); // Notify UI to refresh
}
@@ -1096,9 +1075,8 @@ export class ReviewScheduleService {
}
}
}
- console.log(`Converted ${convertedCount} FSRS cards to SM-2.`);
if (this.plugin.events) {
this.plugin.events.emit('sidebar-update'); // Notify UI to refresh
}
}
-}
+}
\ No newline at end of file
diff --git a/ui/batch-review-modal.ts b/ui/batch-review-modal.ts
index 9e84bba..8b66f4b 100644
--- a/ui/batch-review-modal.ts
+++ b/ui/batch-review-modal.ts
@@ -164,7 +164,6 @@ export class BatchReviewModal extends Modal {
this.allMCQSets,
(results: Array<{ path: string, success: boolean, response: ReviewResponse, score?: number }>) => {
this.results = results;
- console.log("Consolidated MCQ review complete with results:", results);
this.recordAllReviews(results).then(() => {
this.open();
this.showSummary();
@@ -172,7 +171,6 @@ export class BatchReviewModal extends Modal {
}
);
consolidatedModal.open();
- console.log(`Opened consolidated MCQ modal with ${this.allMCQSets.length} MCQ sets`);
} catch (error) {
console.error("Error showing consolidated MCQ UI:", error);
new Notice("Error showing MCQ review. Falling back to manual review.");
diff --git a/ui/consolidated-mcq-modal.ts b/ui/consolidated-mcq-modal.ts
index f45c70c..022f68e 100644
--- a/ui/consolidated-mcq-modal.ts
+++ b/ui/consolidated-mcq-modal.ts
@@ -138,13 +138,9 @@ export class ConsolidatedMCQModal extends Modal {
progressEl.setText(`Question ${this.currentQuestionIndex + 1} of ${this.allQuestions.length}`);
// Display a progress counter badge
- const progressCounter = contentEl.createDiv();
- progressCounter.style.textAlign = 'center';
- progressCounter.style.marginBottom = '12px';
- progressCounter.style.fontSize = '0.9em';
- progressCounter.style.color = 'var(--mcq-text-muted)';
+ const progressCounter = contentEl.createDiv('mcq-progress-counter');
progressCounter.setText(`${this.allQuestions.length} questions from ${this.mcqSets.length} notes`);
-
+
// Display note information with enhanced styling
const noteInfoEl = contentEl.createDiv('mcq-note-info');
noteInfoEl.setText(`Question from: ${this.allQuestions[this.currentQuestionIndex].fileName}`);
@@ -527,11 +523,8 @@ export class ConsolidatedMCQModal extends Modal {
contentEl.empty();
// Display results header with stylized heading
- const headerEl = contentEl.createEl('h2', { text: 'MCQ Review Complete' });
- headerEl.style.color = 'var(--mcq-primary)';
- headerEl.style.textAlign = 'center';
- headerEl.style.marginBottom = '24px';
-
+ const headerEl = contentEl.createEl('h2', { text: 'MCQ Review Complete', cls: 'mcq-review-complete-header' });
+
// Display overall score with enhanced styling
const totalCorrectOverall = this.answers.filter(a => a.correct && a.attempts <= 1).length;
const totalQuestionsOverall = this.allQuestions.length;
@@ -543,35 +536,29 @@ export class ConsolidatedMCQModal extends Modal {
scoreTextEl.setText(`Overall Score: ${scorePercentOverall}%`);
// Add performance indicator based on score
- const performanceIndicator = scoreEl.createDiv();
- performanceIndicator.style.marginTop = '8px';
- performanceIndicator.style.fontSize = '1.1em';
-
+ const performanceIndicator = scoreEl.createDiv('mcq-performance-indicator');
+
if (scorePercentOverall >= 90) {
performanceIndicator.setText('🎓 Excellent Performance!');
- performanceIndicator.style.color = 'var(--mcq-correct)';
+ performanceIndicator.addClass('excellent');
} else if (scorePercentOverall >= 70) {
performanceIndicator.setText('👍 Good Work!');
- performanceIndicator.style.color = 'var(--mcq-primary)';
+ performanceIndicator.addClass('good');
} else if (scorePercentOverall >= 50) {
performanceIndicator.setText('🔄 Keep Practicing');
- performanceIndicator.style.color = 'var(--mcq-warning)';
+ performanceIndicator.addClass('needs-improvement');
} else {
performanceIndicator.setText('📚 More Review Recommended');
- performanceIndicator.style.color = 'var(--mcq-text-muted)';
+ performanceIndicator.addClass('review-recommended');
}
-
+
// Add stats summary
- const statsEl = scoreEl.createDiv();
- statsEl.style.marginTop = '12px';
- statsEl.style.fontSize = '0.9em';
- statsEl.style.color = 'var(--mcq-text-muted)';
+ const statsEl = scoreEl.createDiv('mcq-stats-summary');
statsEl.setText(`${totalCorrectOverall} correct out of ${totalQuestionsOverall} questions`);
-
+
// Display note scores with enhanced styling
const noteScoresEl = contentEl.createDiv('mcq-note-scores');
- const scoreHeading = noteScoresEl.createEl('h3', { text: 'Scores by Note' });
- scoreHeading.style.marginTop = '20px'; // Added margin
+ const scoreHeading = noteScoresEl.createEl('h3', { text: 'Scores by Note', cls: 'mcq-note-scores-heading' });
// Sort notes by score for better visualization (highest first)
const sortedNotes = Object.keys(noteScores).sort((a, b) => noteScores[b].score - noteScores[a].score);
@@ -592,75 +579,51 @@ export class ConsolidatedMCQModal extends Modal {
text: `Score: ${scorePercent}% (${noteScore.correctAnswers}/${noteScore.totalQuestions})`,
cls: 'mcq-note-score-value'
});
-
+
// Style score badge based on performance
if (noteScore.score >= 0.7) {
- scoreTextValueEl.style.backgroundColor = 'rgba(76, 175, 80, 0.1)';
- scoreTextValueEl.style.color = 'var(--mcq-correct)';
- scoreTextValueEl.style.border = '1px solid var(--mcq-correct)';
+ scoreTextValueEl.addClass('high-score');
} else if (noteScore.score >= 0.5) {
- scoreTextValueEl.style.backgroundColor = 'rgba(255, 152, 0, 0.1)';
- scoreTextValueEl.style.color = 'var(--mcq-warning)';
- scoreTextValueEl.style.border = '1px solid var(--mcq-warning)';
+ scoreTextValueEl.addClass('medium-score');
} else {
- scoreTextValueEl.style.backgroundColor = 'rgba(244, 67, 54, 0.1)';
- scoreTextValueEl.style.color = 'var(--mcq-incorrect)';
- scoreTextValueEl.style.border = '1px solid var(--mcq-incorrect)';
+ scoreTextValueEl.addClass('low-score');
}
-
+
// Add a visual progress bar
- const progressBar = noteScoreEl.createDiv();
- progressBar.style.height = '4px';
- progressBar.style.backgroundColor = 'var(--background-modifier-border)';
- progressBar.style.borderRadius = '2px';
- progressBar.style.marginTop = '6px';
- progressBar.style.position = 'relative';
- progressBar.style.overflow = 'hidden';
-
- const progressFill = progressBar.createDiv();
- progressFill.style.position = 'absolute';
- progressFill.style.left = '0';
- progressFill.style.top = '0';
- progressFill.style.height = '100%';
+ const progressBar = noteScoreEl.createDiv('mcq-progress-bar');
+ const progressFill = progressBar.createDiv('mcq-progress-fill');
progressFill.style.width = `${scorePercent}%`;
- progressFill.style.transition = 'width 0.5s ease';
-
+
if (noteScore.score >= 0.7) {
- progressFill.style.backgroundColor = 'var(--mcq-correct)';
+ progressFill.addClass('high-score');
} else if (noteScore.score >= 0.5) {
- progressFill.style.backgroundColor = 'var(--mcq-warning)';
+ progressFill.addClass('medium-score');
} else {
- progressFill.style.backgroundColor = 'var(--mcq-incorrect)';
+ progressFill.addClass('low-score');
}
}
// --- Detailed Question Breakdown ---
const breakdownContainer = contentEl.createDiv('mcq-detailed-breakdown');
- breakdownContainer.style.marginTop = '24px';
breakdownContainer.createEl('h3', { text: 'Detailed Question Breakdown' });
this.allQuestions.forEach((question, index) => {
const questionEl = breakdownContainer.createDiv('mcq-breakdown-item');
- questionEl.style.marginBottom = '12px';
- questionEl.style.padding = '8px';
- questionEl.style.border = '1px solid var(--background-modifier-border)';
- questionEl.style.borderRadius = '4px';
const questionHeader = questionEl.createDiv();
questionHeader.createSpan({ text: `Q${index + 1} (from ${question.fileName}): `, cls: 'mcq-breakdown-q-header' });
questionHeader.createSpan({ text: question.question });
-
+
const userAnswer = this.answers.find(a => a.questionIndex === index);
-
- const userAnswerTextEl = questionEl.createDiv();
- userAnswerTextEl.style.marginLeft = '10px';
+
+ const userAnswerTextEl = questionEl.createDiv('mcq-user-answer-text');
let userAnswerDisplay = "Not answered";
if (userAnswer && userAnswer.selectedAnswerIndex !== -1 && userAnswer.selectedAnswerIndex < question.choices.length) {
userAnswerDisplay = question.choices[userAnswer.selectedAnswerIndex];
} else if (userAnswer && userAnswer.selectedAnswerIndex === -1) {
// This case should ideally not happen with the new logic in handleAnswer
// but good to have a fallback.
- userAnswerDisplay = "Attempted, but no valid choice recorded";
+ userAnswerDisplay = "Attempted, but no valid choice recorded";
}
@@ -668,33 +631,27 @@ export class ConsolidatedMCQModal extends Modal {
const correctnessText = userAnswer.correct ? ' (Correct)' : ' (Incorrect)';
userAnswerTextEl.createSpan({ text: 'Your answer: ' });
const userAnswerSpan = userAnswerTextEl.createSpan({ text: userAnswerDisplay });
- const correctnessSpan = userAnswerTextEl.createSpan({ text: correctnessText });
- correctnessSpan.style.fontWeight = 'bold';
+ const correctnessSpan = userAnswerTextEl.createSpan({ text: correctnessText, cls: 'mcq-correctness-indicator' });
if (userAnswer.correct) {
- userAnswerSpan.style.color = 'var(--mcq-correct)';
- correctnessSpan.style.color = 'var(--mcq-correct)';
+ userAnswerSpan.addClass('correct');
+ correctnessSpan.addClass('correct');
} else {
- userAnswerSpan.style.color = 'var(--mcq-incorrect)';
- correctnessSpan.style.color = 'var(--mcq-incorrect)';
+ userAnswerSpan.addClass('incorrect');
+ correctnessSpan.addClass('incorrect');
}
} else {
- userAnswerTextEl.createSpan({ text: 'Your answer: ' + userAnswerDisplay });
- userAnswerTextEl.style.fontStyle = 'italic';
+ userAnswerTextEl.createSpan({ text: 'Your answer: ' + userAnswerDisplay });
+ userAnswerTextEl.style.fontStyle = 'italic';
}
- const correctAnswerEl = questionEl.createDiv();
- correctAnswerEl.style.marginLeft = '10px';
+ const correctAnswerEl = questionEl.createDiv('mcq-correct-answer');
correctAnswerEl.createSpan({ text: 'Correct answer: ' });
- const correctAnswerSpan = correctAnswerEl.createSpan({ text: question.choices[question.correctAnswerIndex] });
- correctAnswerSpan.style.color = 'var(--mcq-correct-answer-text)'; // A distinct color for the correct answer text itself
- correctAnswerSpan.style.fontWeight = 'bold';
+ correctAnswerEl.createSpan({ text: question.choices[question.correctAnswerIndex], cls: 'mcq-correct-answer-text' });
});
// Create close button
- const closeBtn = contentEl.createEl('button', 'mcq-close-btn');
- closeBtn.setText('Close');
- closeBtn.style.marginTop = '24px'; // Added margin
-
+ const closeBtn = contentEl.createEl('button', {cls: 'mcq-close-btn', text: 'Close'});
+
closeBtn.addEventListener('click', () => {
this.close();
});
diff --git a/ui/context-menu.ts b/ui/context-menu.ts
index 98dcad5..f146c09 100644
--- a/ui/context-menu.ts
+++ b/ui/context-menu.ts
@@ -28,7 +28,6 @@ export class ContextMenuHandler {
this.plugin.registerEvent(
this.plugin.app.workspace.on("file-menu", this.handleFileMenuEvent.bind(this))
);
- console.log("Unified context menu handler registered for 'file-menu'.");
}
/**
@@ -40,11 +39,9 @@ export class ContextMenuHandler {
handleFileMenuEvent(menu: Menu, abstractFile: TAbstractFile): void {
if (abstractFile instanceof TFolder) {
// Handle folder context menu
- console.log("Folder right-clicked:", abstractFile.path);
this.addFolderMenuItems(menu, abstractFile);
} else if (abstractFile instanceof TFile && abstractFile.extension === "md") {
// Handle markdown file context menu
- console.log("Markdown file right-clicked:", abstractFile.path);
this.addFileMenuItems(menu, abstractFile);
}
}
@@ -113,17 +110,14 @@ export class ContextMenuHandler {
* @param folder Target folder
*/
private addFolderMenuItems(menu: Menu, folder: TFolder): void {
- console.log("Adding menu items for folder:", folder.path);
try {
menu.addItem((item) => {
item.setTitle("Add folder to review")
.setIcon("calendar-plus")
.onClick(() => {
- console.log("Context menu: Adding folder to review:", folder.path);
this.addFolderToReview(folder);
});
});
- console.log("Menu items added successfully for folder:", folder.path);
} catch (error) {
console.error("Error adding folder menu items:", error);
}
@@ -135,7 +129,6 @@ export class ContextMenuHandler {
* @param folder Target folder
*/
async addFolderToReview(folder: TFolder): Promise {
- console.log("Processing folder:", folder.path);
// Show immediate notification
new Notice(`Analyzing folder structure for "${folder.name}"...`);
@@ -174,7 +167,6 @@ export class ContextMenuHandler {
// Exact match first
if (fileName === folderName) {
mainFilePath = file.path;
- console.log(`Found main file with exact folder name match: ${mainFilePath}`);
break;
}
}
@@ -192,7 +184,6 @@ export class ContextMenuHandler {
fileName.includes('index') ||
fileName.includes('main')) {
mainFilePath = file.path;
- console.log(`Found main file by partial name match: ${mainFilePath}`);
break;
}
}
@@ -205,7 +196,6 @@ export class ContextMenuHandler {
activeFile.extension === "md" &&
allFiles.some(f => f.path === activeFile.path)) {
mainFilePath = activeFile.path;
- console.log(`Using active note as main file: ${mainFilePath}`);
}
}
@@ -218,7 +208,6 @@ export class ContextMenuHandler {
}
visited.add(path);
traversalOrder.push(path);
- // console.log(`Added to traversal: ${path}`); // Keep console logs minimal for production
const links = await LinkAnalyzer.analyzeNoteLinks(
this.plugin.app.vault,
@@ -238,7 +227,6 @@ export class ContextMenuHandler {
if (!visited.has(linkFile.path)) {
visited.add(linkFile.path);
traversalOrder.push(linkFile.path);
- // console.log(`Added external link (no recursion): ${linkFile.path}`);
}
}
}
@@ -246,7 +234,6 @@ export class ContextMenuHandler {
// If a mainFilePath was identified, process it first.
if (mainFilePath) {
- console.log(`Starting traversal from identified main file: ${mainFilePath}`);
await processLinksRecursively(mainFilePath);
}
@@ -256,12 +243,10 @@ export class ContextMenuHandler {
const sortedAllFiles = [...allFiles].sort((a,b) => a.path.localeCompare(b.path));
for (const file of sortedAllFiles) {
if (!visited.has(file.path)) {
- console.log(`Processing new branch or unlinked file: ${file.path}`);
await processLinksRecursively(file.path);
}
}
- console.log(`Final traversal order determined with ${traversalOrder.length} files.`);
// Schedule notes in the traversal order using the service
const count = await this.plugin.reviewScheduleService.scheduleNotesInOrder(traversalOrder);
diff --git a/ui/mcq-modal.ts b/ui/mcq-modal.ts
index 646f289..f9d93dd 100644
--- a/ui/mcq-modal.ts
+++ b/ui/mcq-modal.ts
@@ -223,24 +223,36 @@ export class MCQModal extends Modal {
const existingAnswer = this.session.answers.find(a => a.questionIndex === questionIndex);
if (existingAnswer && existingAnswer.attempts >= 2) {
const skipContainer = newQuestionContainer.createDiv('mcq-skip-container');
- skipContainer.style.marginBottom = '12px'; skipContainer.style.textAlign = 'right';
const skipButton = skipContainer.createEl('button', { text: 'Show Answer & Continue', cls: 'mcq-skip-button' });
- skipButton.style.backgroundColor = 'var(--text-muted)'; skipButton.style.color = 'white'; skipButton.style.padding = '4px 8px'; skipButton.style.borderRadius = '4px'; skipButton.style.cursor = 'pointer'; skipButton.style.border = 'none';
skipButton.addEventListener('click', () => {
const correctIndex = question.correctAnswerIndex;
const correctAnswerDisplay = newQuestionContainer.createDiv('mcq-correct-answer-display');
- correctAnswerDisplay.style.backgroundColor = 'rgba(76, 175, 80, 0.1)'; correctAnswerDisplay.style.padding = '10px'; correctAnswerDisplay.style.borderRadius = '4px'; correctAnswerDisplay.style.marginBottom = '10px'; correctAnswerDisplay.style.border = '1px solid #4caf50';
- const correctLabel = correctAnswerDisplay.createDiv(); correctLabel.style.fontWeight = 'bold'; correctLabel.style.marginBottom = '4px'; correctLabel.setText('Correct Answer:');
- const correctText = correctAnswerDisplay.createDiv(); correctText.style.color = '#4caf50'; correctText.setText(String.fromCharCode(65 + correctIndex) + ') ' + question.choices[correctIndex]);
+ const correctLabel = correctAnswerDisplay.createDiv();
+ correctLabel.style.fontWeight = 'bold';
+ correctLabel.style.marginBottom = '4px';
+ correctLabel.setText('Correct Answer:');
+ const correctText = correctAnswerDisplay.createDiv();
+ correctText.style.color = '#4caf50';
+ correctText.setText(String.fromCharCode(65 + correctIndex) + ') ' + question.choices[correctIndex]);
if (existingAnswer) {
- existingAnswer.selectedAnswerIndex = -1; existingAnswer.correct = false; existingAnswer.attempts += 1;
+ existingAnswer.selectedAnswerIndex = -1;
+ existingAnswer.correct = false;
+ existingAnswer.attempts += 1;
} else {
- this.session.answers.push({ questionIndex, selectedAnswerIndex: -1, correct: false, timeToAnswer: (Date.now() - this.questionStartTime) / 1000, attempts: 3 });
+ this.session.answers.push({
+ questionIndex,
+ selectedAnswerIndex: -1,
+ correct: false,
+ timeToAnswer: (Date.now() - this.questionStartTime) / 1000,
+ attempts: 3
+ });
}
- const continueBtn = correctAnswerDisplay.createEl('button', { text: 'Continue to Next Question', cls: 'mcq-continue-button' });
- continueBtn.style.marginTop = '10px'; continueBtn.style.backgroundColor = 'var(--interactive-accent)'; continueBtn.style.color = 'white'; continueBtn.style.padding = '6px 12px'; continueBtn.style.borderRadius = '4px'; continueBtn.style.cursor = 'pointer'; continueBtn.style.border = 'none';
+ const continueBtn = correctAnswerDisplay.createEl('button', {
+ text: 'Continue to Next Question',
+ cls: 'mcq-continue-button'
+ });
continueBtn.addEventListener('click', () => {
this.session.currentQuestionIndex++;
this.questionStartTime = Date.now();
@@ -266,7 +278,6 @@ export class MCQModal extends Modal {
const letterLabel = choiceBtn.createSpan('mcq-choice-letter'); letterLabel.setText(String.fromCharCode(65 + index) + ') ');
const textSpan = choiceBtn.createSpan('mcq-choice-text'); textSpan.setText(choice || '(Empty choice)');
const shortcutHint = choiceBtn.createSpan('mcq-shortcut-hint');
- shortcutHint.style.fontSize = '0.8em'; shortcutHint.style.color = 'var(--mcq-text-muted)'; shortcutHint.style.marginLeft = 'auto'; shortcutHint.style.paddingLeft = '10px';
shortcutHint.setText(`${String.fromCharCode(65 + index)} or ${index + 1}`);
choiceBtn.addEventListener('click', () => this.handleAnswer(index));
});
@@ -286,7 +297,6 @@ export class MCQModal extends Modal {
if (isCorrect) { answer.selectedAnswerIndex = selectedIndex; answer.correct = true; }
answer.timeToAnswer = timeToAnswer; answer.attempts += 1;
if (answer.attempts >= 2 && !answer.correct) {
- console.log(`Question ${questionIndex+1} has ${answer.attempts} attempts, marking as zero points`);
answer.selectedAnswerIndex = -1; // Mark as failed but eventually correct
}
} else {
@@ -333,7 +343,7 @@ export class MCQModal extends Modal {
this.plugin.mcqService.saveMCQSession(this.session);
this.plugin.savePluginData(); // Persist
- contentEl.createEl('h2').setText('Review Complete'); // Corrected
+ contentEl.createEl('h2', { text: 'Review Complete' });
const scoreEl = contentEl.createDiv('mcq-score');
const scoreTextEl = scoreEl.createDiv('mcq-score-text');
const scorePercentage = this.session.score; // Score is 0-1
@@ -380,56 +390,52 @@ export class MCQModal extends Modal {
if (ratingDetails) {
const detailsEl = scoreEl.createDiv('mcq-score-details');
detailsEl.setText(ratingDetails);
- detailsEl.style.fontSize = '0.9em';
- detailsEl.style.color = 'var(--text-muted)';
- detailsEl.style.marginTop = '4px';
}
// Removed the old score indicator text (🎯 Excellent, etc.)
const resultsEl = contentEl.createDiv('mcq-results');
- resultsEl.createEl('h3').setText('Question Results');
+ resultsEl.createEl('h3', { text: 'Question Results' });
if (this.session.answers.length === 0) {
- resultsEl.createDiv('mcq-no-answers').setText('No questions were answered in this session.');
+ resultsEl.createDiv({ cls: 'mcq-no-answers', text: 'No questions were answered in this session.' });
} else {
this.session.answers.forEach(answer => {
try {
const question = this.mcqSet.questions[answer.questionIndex];
if (!question || !question.choices) return;
const resultItem = resultsEl.createDiv('mcq-result-item');
- resultItem.createDiv('mcq-result-question').setText(question.question || 'Question text missing');
+ resultItem.createDiv({ cls: 'mcq-result-question', text: question.question || 'Question text missing' });
if (answer.attempts > 1) {
if (answer.selectedAnswerIndex !== -1) {
const yourAnswer = resultItem.createDiv('mcq-result-your-answer');
- yourAnswer.createSpan('mcq-result-label').setText('Your final answer (correct after multiple attempts): ');
- yourAnswer.createSpan('mcq-result-correct').setText(question.choices[answer.selectedAnswerIndex] || '(invalid choice)');
+ yourAnswer.createSpan({ cls: 'mcq-result-label', text: 'Your final answer (correct after multiple attempts): ' });
+ yourAnswer.createSpan({ cls: 'mcq-result-correct', text: question.choices[answer.selectedAnswerIndex] || '(invalid choice)' });
} else {
const yourAnswer = resultItem.createDiv('mcq-result-your-answer');
- yourAnswer.createSpan('mcq-result-label').setText('Your answer: ');
- yourAnswer.createSpan('mcq-result-incorrect').setText('(Incorrect - used "Show Answer" option)');
+ yourAnswer.createSpan({ cls: 'mcq-result-label', text: 'Your answer: ' });
+ yourAnswer.createSpan({ cls: 'mcq-result-incorrect', text: '(Incorrect - used "Show Answer" option)' });
}
const correctAnswer = resultItem.createDiv('mcq-result-correct-answer');
- correctAnswer.createSpan('mcq-result-label').setText('Correct answer: ');
- correctAnswer.createSpan('mcq-result-correct').setText(question.choices[question.correctAnswerIndex] || '(invalid choice)');
+ correctAnswer.createSpan({ cls: 'mcq-result-label', text: 'Correct answer: ' });
+ correctAnswer.createSpan({ cls: 'mcq-result-correct', text: question.choices[question.correctAnswerIndex] || '(invalid choice)' });
} else {
const yourAnswer = resultItem.createDiv('mcq-result-your-answer');
- yourAnswer.createSpan('mcq-result-label').setText('Your answer: ');
- yourAnswer.createSpan(answer.correct ? 'mcq-result-correct' : 'mcq-result-incorrect').setText(question.choices[answer.selectedAnswerIndex] || '(invalid choice)');
+ yourAnswer.createSpan({ cls: 'mcq-result-label', text: 'Your answer: ' });
+ yourAnswer.createSpan({ cls: answer.correct ? 'mcq-result-correct' : 'mcq-result-incorrect', text: question.choices[answer.selectedAnswerIndex] || '(invalid choice)' });
if (!answer.correct) {
const correctAnswer = resultItem.createDiv('mcq-result-correct-answer');
- correctAnswer.createSpan('mcq-result-label').setText('Correct answer: ');
- correctAnswer.createSpan('mcq-result-correct').setText(question.choices[question.correctAnswerIndex] || '(invalid choice)');
+ correctAnswer.createSpan({ cls: 'mcq-result-label', text: 'Correct answer: ' });
+ correctAnswer.createSpan({ cls: 'mcq-result-correct', text: question.choices[question.correctAnswerIndex] || '(invalid choice)' });
}
}
- resultItem.createDiv('mcq-result-attempts').setText(`Attempts: ${answer.attempts}`);
- resultItem.createDiv('mcq-result-time').setText(`Time: ${Math.round(answer.timeToAnswer)} seconds`);
+ resultItem.createDiv({ cls: 'mcq-result-attempts', text: `Attempts: ${answer.attempts}` });
+ resultItem.createDiv({ cls: 'mcq-result-time', text: `Time: ${Math.round(answer.timeToAnswer)} seconds` });
// FSRS/SM-2 data per question removed from here
} catch (error) { console.error('Error displaying answer result:', error); }
});
}
- const closeBtn = contentEl.createEl('button', { cls: 'mcq-close-btn' });
- closeBtn.setText('Close');
+ const closeBtn = contentEl.createEl('button', { cls: 'mcq-close-btn', text: 'Close' });
closeBtn.addEventListener('click', () => {
if (this.onCompleteCallback) {
// Pass the actual score and completion status
@@ -439,10 +445,9 @@ export class MCQModal extends Modal {
});
} catch (error) {
console.error('Error completing MCQ session:', error);
- contentEl.createEl('h2').setText('Error Completing Session'); // Corrected
- contentEl.createEl('p').setText('There was an error completing the MCQ session. Please try again.'); // Corrected
- const errorCloseBtn = contentEl.createEl('button', { cls: 'mcq-close-btn' });
- errorCloseBtn.setText('Close'); // Set text separately
+ contentEl.createEl('h2', { text: 'Error Completing Session' });
+ contentEl.createEl('p', { text: 'There was an error completing the MCQ session. Please try again.' });
+ const errorCloseBtn = contentEl.createEl('button', { cls: 'mcq-close-btn', text: 'Close' });
errorCloseBtn.addEventListener('click', () => this.close());
}
}
@@ -500,4 +505,4 @@ function getSm2RatingText(rating: number): string {
case 5: return "Perfect Recall";
default: return "Unknown";
}
-}
+}
\ No newline at end of file
diff --git a/ui/review-modal.ts b/ui/review-modal.ts
index c646f59..fcd8cb8 100644
--- a/ui/review-modal.ts
+++ b/ui/review-modal.ts
@@ -129,6 +129,7 @@ export class ReviewModal extends Modal {
// Note Info Section
const infoText = contentEl.createDiv("review-info-text");
+ infoText.empty();
// const schedule = this.plugin.reviewScheduleService.schedules[this.path]; // Already fetched
if (schedule) {
@@ -171,6 +172,5 @@ export class ReviewModal extends Modal {
onClose(): void {
const { contentEl } = this;
contentEl.empty();
- console.log("Review modal closed for path: " + this.path);
}
}
diff --git a/ui/settings-tab.ts b/ui/settings-tab.ts
index 9c8a05b..83a4fa0 100644
--- a/ui/settings-tab.ts
+++ b/ui/settings-tab.ts
@@ -1,7 +1,7 @@
import { App, Notice, PluginSettingTab, Setting, setIcon, TextAreaComponent } from 'obsidian'; // Added TextAreaComponent
import SpaceforgePlugin from '../main';
// Import ApiProvider, DEFAULT_SETTINGS, SpaceforgeSettings, and MCQQuestionAmountMode
-import { ApiProvider, DEFAULT_SETTINGS, SpaceforgeSettings, MCQQuestionAmountMode } from '../models/settings';
+import { ApiProvider, DEFAULT_SETTINGS, SpaceforgeSettings, MCQQuestionAmountMode, MCQDifficulty } from '../models/settings';
import { SpaceforgePluginData, DEFAULT_APP_DATA, DEFAULT_PLUGIN_STATE_DATA } from '../models/plugin-data'; // Import data structures
/**
@@ -603,7 +603,6 @@ export class SpaceforgeSettingTab extends PluginSettingTab {
openRouterModel: this.plugin.settings.openRouterModel
};
window.localStorage.setItem('spaceforge-api-settings', JSON.stringify(apiSettings));
- console.log("Updated API settings backup with MCQ state");
} catch (e) {
console.error("Error updating API settings backup:", e);
}
@@ -660,7 +659,7 @@ export class SpaceforgeSettingTab extends PluginSettingTab {
await this.plugin.savePluginData();
}));
// Removed sf-setting-explain class
- apiKeyContainer.createEl('div', { text: 'Get your API key at https://openrouter.ai/keys' });
+ apiKeyContainer.createEl('div').setText('Get your API key at https://openrouter.ai/keys');
new Setting(mcqSection)
.setName('OpenRouter Model')
@@ -901,11 +900,11 @@ export class SpaceforgeSettingTab extends PluginSettingTab {
.setName('MCQ difficulty')
.setDesc('Complexity level')
.addDropdown(dropdown => dropdown
- .addOption('basic', 'Basic recall')
- .addOption('advanced', 'Advanced understanding')
+ .addOption(MCQDifficulty.Basic, 'Basic recall')
+ .addOption(MCQDifficulty.Advanced, 'Advanced understanding')
.setValue(this.plugin.settings.mcqDifficulty)
- .onChange(async (value: string) => {
- this.plugin.settings.mcqDifficulty = value as any;
+ .onChange(async (value: MCQDifficulty) => {
+ this.plugin.settings.mcqDifficulty = value;
await this.plugin.savePluginData();
}));
@@ -1157,15 +1156,32 @@ export class SpaceforgeSettingTab extends PluginSettingTab {
sm2List.createEl('li', { text: 'Both cases reset the repetition count to 1 and update the ease factor.' });
const ratingsTable = container.createEl('table', { cls: 'sf-ratings-table' }); // Added a class for potential styling
- ratingsTable.innerHTML = `
- | Rating (0-5) | Description | Effect on Interval |
-
- | 0-2 | Incorrect / struggled | Resets, shortest interval |
- | 3 | Correct with difficulty | Small increase |
- | 4 | Correct with hesitation | Moderate increase |
- | 5 | Perfect recall | Largest increase |
-
- `;
+ const thead = ratingsTable.createTHead();
+ const tbody = ratingsTable.createTBody();
+ const headerRow = thead.insertRow();
+ headerRow.createEl('th', { text: 'Rating (0-5)' });
+ headerRow.createEl('th', { text: 'Description' });
+ headerRow.createEl('th', { text: 'Effect on Interval' });
+
+ const row1 = tbody.insertRow();
+ row1.createEl('td', { text: '0-2' });
+ row1.createEl('td', { text: 'Incorrect / struggled' });
+ row1.createEl('td', { text: 'Resets, shortest interval' });
+
+ const row2 = tbody.insertRow();
+ row2.createEl('td', { text: '3' });
+ row2.createEl('td', { text: 'Correct with difficulty' });
+ row2.createEl('td', { text: 'Small increase' });
+
+ const row3 = tbody.insertRow();
+ row3.createEl('td', { text: '4' });
+ row3.createEl('td', { text: 'Correct with hesitation' });
+ row3.createEl('td', { text: 'Moderate increase' });
+
+ const row4 = tbody.insertRow();
+ row4.createEl('td', { text: '5' });
+ row4.createEl('td', { text: 'Perfect recall' });
+ row4.createEl('td', { text: 'Largest increase' });
} else if (algorithm === 'fsrs') {
container.createEl('h4', { text: 'About the FSRS Algorithm' });
container.createEl('p', {
@@ -1182,15 +1198,32 @@ export class SpaceforgeSettingTab extends PluginSettingTab {
fsrsList.createEl('li', { text: 'Learning Steps: Initial short intervals for new cards (configurable).' });
const ratingsTable = container.createEl('table', { cls: 'sf-ratings-table' });
- ratingsTable.innerHTML = `
- | Rating (1-4) | Description | Effect on Stability/Difficulty |
-
- | 1 (Again) | Forgot the card | Decreases stability, may increase difficulty |
- | 2 (Hard) | Recalled with significant difficulty | Smaller increase in stability |
- | 3 (Good) | Recalled correctly | Standard increase in stability |
- | 4 (Easy) | Recalled very easily | Largest increase in stability, may decrease difficulty |
-
- `;
+ const thead = ratingsTable.createTHead();
+ const tbody = ratingsTable.createTBody();
+ const headerRow = thead.insertRow();
+ headerRow.createEl('th', { text: 'Rating (1-4)' });
+ headerRow.createEl('th', { text: 'Description' });
+ headerRow.createEl('th', { text: 'Effect on Stability/Difficulty' });
+
+ const row1 = tbody.insertRow();
+ row1.createEl('td', { text: '1 (Again)' });
+ row1.createEl('td', { text: 'Forgot the card' });
+ row1.createEl('td', { text: 'Decreases stability, may increase difficulty' });
+
+ const row2 = tbody.insertRow();
+ row2.createEl('td', { text: '2 (Hard)' });
+ row2.createEl('td', { text: 'Recalled with significant difficulty' });
+ row2.createEl('td', { text: 'Smaller increase in stability' });
+
+ const row3 = tbody.insertRow();
+ row3.createEl('td', { text: '3 (Good)' });
+ row3.createEl('td', { text: 'Recalled correctly' });
+ row3.createEl('td', { text: 'Standard increase in stability' });
+
+ const row4 = tbody.insertRow();
+ row4.createEl('td', { text: '4 (Easy)' });
+ row4.createEl('td', { text: 'Recalled very easily' });
+ row4.createEl('td', { text: 'Largest increase in stability, may decrease difficulty' });
container.createEl('p', {text: 'FSRS parameters (weights, retention, etc.) can be tuned, but the defaults are generally effective.'});
}
}
diff --git a/ui/sidebar-view.ts b/ui/sidebar-view.ts
index db35324..9efb275 100644
--- a/ui/sidebar-view.ts
+++ b/ui/sidebar-view.ts
@@ -30,6 +30,7 @@ export class ReviewSidebarView extends ItemView {
private lastSelectedNotePath: string | null = null;
private lastScrollPosition: number = 0;
private expandedUpcomingDayKey: string | null = null; // State for upcoming section
+ private resizeObserver: ResizeObserver | null = null;
// Sub-components for rendering different parts
private pomodoroUIManager: PomodoroUIManager;
@@ -67,15 +68,15 @@ export class ReviewSidebarView extends ItemView {
}
async onClose(): Promise {
- if ((this as any).resizeObserver) {
- (this as any).resizeObserver.disconnect();
+ if (this.resizeObserver) {
+ this.resizeObserver.disconnect();
}
this.plugin.events.off('sidebar-update', this.refresh.bind(this));
// No need to explicitly unregister pomodoro-update as the manager handles its own logic
}
private ensureBaseStructure(): void {
- const contentEl = this.containerEl || (this as any).contentEl;
+ const contentEl = this.containerEl;
if (!contentEl) return;
if (!this.mainContainer) {
@@ -280,7 +281,7 @@ export class ReviewSidebarView extends ItemView {
if (this.containerEl) {
resizeObserver.observe(this.containerEl);
- (this as any).resizeObserver = resizeObserver;
+ this.resizeObserver = resizeObserver;
this.updateCalendarContainerClass();
}
}
@@ -389,7 +390,7 @@ export class ReviewSidebarView extends ItemView {
};
}
- async setViewState(state: ReviewSidebarViewState, e?: any): Promise {
+ async setViewState(state: ReviewSidebarViewState): Promise {
if (!state) return;
// Restore non-UI-dependent state first
diff --git a/ui/sidebar/note-item-renderer.ts b/ui/sidebar/note-item-renderer.ts
index e1e57c7..a17642c 100644
--- a/ui/sidebar/note-item-renderer.ts
+++ b/ui/sidebar/note-item-renderer.ts
@@ -58,11 +58,9 @@ export class NoteItemRenderer {
if (note.scheduleCategory === 'initial') {
const totalInitialSteps = this.plugin.settings.initialScheduleCustomIntervals.length;
const currentStepDisplay = note.reviewCount < totalInitialSteps ? note.reviewCount + 1 : totalInitialSteps;
- phaseEl.innerHTML = `
- Initial
- ${currentStepDisplay}/${totalInitialSteps}
- ${formattedTime}
- `;
+ phaseEl.createDiv({ title: "Initial", text: "Initial" });
+ phaseEl.createDiv({ title: `${currentStepDisplay}/${totalInitialSteps}`, text: `${currentStepDisplay}/${totalInitialSteps}` });
+ const phaseTimeEl = phaseEl.createDiv({ cls: "phase-time", title: formattedTime, text: formattedTime });
phaseEl.addClass("review-phase-initial");
} else {
phaseEl.setText(note.scheduleCategory === 'graduated' ? "Graduated" : "Spaced");
diff --git a/utils/link-analyzer.ts b/utils/link-analyzer.ts
index 14c4cae..9fc5d38 100644
--- a/utils/link-analyzer.ts
+++ b/utils/link-analyzer.ts
@@ -250,10 +250,8 @@ export class LinkAnalyzer {
* @returns Array with the path of the best starting node
*/
private static findStartingNode(nodes: Record): string[] {
- console.log("LinkAnalyzer: Starting node selection process...");
// If we have no nodes, return an empty array
if (Object.keys(nodes).length === 0) {
- console.log("LinkAnalyzer: No nodes found, returning empty array.");
return [];
}
@@ -274,42 +272,25 @@ export class LinkAnalyzer {
const filesInFolder = folderNodes[folderPath];
// HIGHEST PRIORITY: Exact match with folder name
- console.log(`LinkAnalyzer: Checking for exact match with folder name "${folderName}" in folder "${folderPath}"...`);
for (const path of filesInFolder) {
- const fileName = path.split('/').pop()?.toLowerCase() || '';
- const fileNameWithoutExt = fileName.replace(/\.md$/, '');
-
- if (fileNameWithoutExt === folderName) {
- console.log(`LinkAnalyzer: Selected main file with exact folder name match: ${path}`);
+ const fileName = path.split('/').pop()?.toLowerCase().replace(/\.md$/, '') || '';
+ if (fileName === folderName) {
return [path];
}
}
-
+
// SECOND PRIORITY: Partial match with folder name
- console.log(`LinkAnalyzer: Checking for partial match with folder name "${folderName}"...`);
for (const path of filesInFolder) {
- const fileName = path.split('/').pop()?.toLowerCase() || '';
- const fileNameWithoutExt = fileName.replace(/\.md$/, '');
-
- if (fileNameWithoutExt.includes(folderName) || folderName.includes(fileNameWithoutExt)) {
- console.log(`LinkAnalyzer: Selected main file with partial folder name match: ${path}`);
+ const fileName = path.split('/').pop()?.toLowerCase().replace(/\.md$/, '') || '';
+ if (fileName.includes(folderName) || folderName.includes(fileName)) {
return [path];
}
}
-
+
// THIRD PRIORITY: Common index or main file patterns
- console.log("LinkAnalyzer: Checking for common index or main file patterns...");
for (const path of filesInFolder) {
- const fileName = path.split('/').pop()?.toLowerCase() || '';
- const fileNameWithoutExt = fileName.replace(/\.md$/, '');
-
- if (fileNameWithoutExt === 'index' ||
- fileNameWithoutExt === 'main' ||
- fileNameWithoutExt.includes('index') ||
- fileNameWithoutExt.includes('readme') ||
- fileNameWithoutExt.includes('main')) {
-
- console.log(`LinkAnalyzer: Selected main file by standard name pattern: ${path}`);
+ const fileName = path.split('/').pop()?.toLowerCase().replace(/\.md$/, '') || '';
+ if (fileName === 'index' || fileName === 'main' || fileName.includes('index') || fileName.includes('readme') || fileName.includes('main')) {
return [path];
}
}
@@ -317,7 +298,6 @@ export class LinkAnalyzer {
// FOURTH PRIORITY: Look for files with the most outgoing links
// Prefer regular links over embeds
- console.log("LinkAnalyzer: Checking for files with the most outgoing links...");
const sortedNodes = Object.values(nodes)
.sort((a, b) => {
// First, prioritize by regular link count (non-embed links)
@@ -333,12 +313,10 @@ export class LinkAnalyzer {
if (sortedNodes.length > 0 &&
(sortedNodes[0].regularLinks.length > 0 || sortedNodes[0].outgoingLinks.length > 0)) {
// Return the node with the most links
- console.log(`LinkAnalyzer: Selected main file by link count: ${sortedNodes[0].path} with ${sortedNodes[0].regularLinks.length} regular links`);
return [sortedNodes[0].path];
}
// FALLBACK: Use all files as root nodes if none of the above criteria match
- console.log(`LinkAnalyzer: No clear main file identified, using first file as root node`);
return Object.keys(nodes).length > 0 ? [Object.keys(nodes)[0]] : [];
}
@@ -376,12 +354,10 @@ export class LinkAnalyzer {
}
const mainFolder = fileFolders.get(startNodePath) || "";
- console.log(`LinkAnalyzer: Starting ordered traversal from: ${startNodePath} in main folder: ${mainFolder || "vault root"}`);
// Helper function for depth-first traversal, respecting link order and folder constraints
const traverse = (currentNodePath: string, currentDepth: number = 0, currentMainFolder: string) => {
if (visited.has(currentNodePath)) {
- console.log(`${" ".repeat(currentDepth)}LinkAnalyzer: Already visited: ${currentNodePath}`);
return;
}
@@ -391,7 +367,6 @@ export class LinkAnalyzer {
return;
}
- console.log(`${" ".repeat(currentDepth)}LinkAnalyzer: Traversing: ${currentNodePath}`);
visited.add(currentNodePath);
traversalOrder.push(currentNodePath);
@@ -402,7 +377,6 @@ export class LinkAnalyzer {
for (const linkedPath of linksToFollow) {
if (!nodes[linkedPath]) { // Ensure the linked path is a known node in the current analysis context
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Skipping unknown linked path: ${linkedPath}`);
continue;
}
@@ -411,14 +385,11 @@ export class LinkAnalyzer {
// MODIFIED RULE: Traverse if the linked note is within the scope of the main analysis folder.
if (nodes[linkedPath] && linkedNodeFolder.startsWith(currentMainFolder)) { // Ensure it's a known node and within the main hierarchy
if (!visited.has(linkedPath)) { // Avoid re-traversing already processed branches
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Following link within main hierarchy to: ${linkedPath}`);
traverse(linkedPath, currentDepth + 1, currentMainFolder);
} else {
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Link to already visited node in main hierarchy: ${linkedPath}`);
}
} else {
// This link goes outside the main folder being analyzed or is not a known node.
- console.log(`${" ".repeat(currentDepth + 1)}LinkAnalyzer: Ignoring link outside main hierarchy or unknown node: ${linkedPath} (from ${currentNodeFolder} to ${linkedNodeFolder})`);
}
}
};
@@ -435,7 +406,6 @@ export class LinkAnalyzer {
// unlinked files from the mainFolder.
// Log the traversal order summary
- console.log(`LinkAnalyzer: Final traversal order from ${startNodePath} (in folder '${mainFolder || "vault root"}') has ${traversalOrder.length} files: ${traversalOrder.join(' -> ')}`);
return traversalOrder;
}
@@ -538,7 +508,6 @@ export class LinkAnalyzer {
}
}
- console.log(`LinkAnalyzer: Analyzed links in ${filePath}, found ${resolvedLinks.length} unique links in order`);
return resolvedLinks;
} catch (error) {