mirror of
https://github.com/sailor-sh/CK-X.git
synced 2026-07-12 09:09:25 +00:00
178 lines
7.8 KiB
JavaScript
178 lines
7.8 KiB
JavaScript
/**
|
|
* Question Service
|
|
* Handles question display and navigation
|
|
*/
|
|
|
|
// Process question content to improve formatting and highlighting
|
|
function processQuestionContent(content) {
|
|
// First, preserve existing HTML formatting
|
|
let processedContent = content;
|
|
|
|
// Add highlighting to text in single quotes that isn't already styled
|
|
processedContent = processedContent.replace(
|
|
/`([^`]+)`/g,
|
|
function(match, text) {
|
|
// Skip if already inside an HTML tag or existing styled element
|
|
if (match.match(/<.*>/) ||
|
|
match.includes('class="code"') ||
|
|
match.includes('class="highlight"')) {
|
|
return match;
|
|
}
|
|
return `<span class="inline-code">${text}</span>`;
|
|
}
|
|
);
|
|
|
|
// Style inline code with backticks if not already styled
|
|
processedContent = processedContent.replace(
|
|
/`([^`]+)`/g,
|
|
'<code class="bg-light px-1 rounded">$1</code>'
|
|
);
|
|
|
|
// Style bold text
|
|
processedContent = processedContent.replace(
|
|
/\*\*([^*]+)\*\*/g,
|
|
'<strong>$1</strong>'
|
|
);
|
|
|
|
// Style italic text
|
|
processedContent = processedContent.replace(
|
|
/\*([^*]+)\*/g,
|
|
'<em>$1</em>'
|
|
);
|
|
|
|
// Convert literal newline characters to HTML line breaks
|
|
processedContent = processedContent.replace(/\n/g, '<br>');
|
|
|
|
// Ensure paragraphs have proper spacing and line breaks
|
|
processedContent = processedContent.replace(
|
|
/<\/p><p>/g,
|
|
'</p>\n<p>'
|
|
);
|
|
|
|
// Add more spacing between list items
|
|
processedContent = processedContent.replace(
|
|
/<\/li><li>/g,
|
|
'</li>\n<li>'
|
|
);
|
|
|
|
return processedContent;
|
|
}
|
|
|
|
// Generate question content HTML
|
|
function generateQuestionContent(question) {
|
|
try {
|
|
// Get original data
|
|
const originalData = question.originalData || {};
|
|
const machineHostname = originalData.machineHostname || 'N/A';
|
|
const namespace = originalData.namespace || 'N/A';
|
|
const concepts = originalData.concepts || [];
|
|
const conceptsString = concepts.join(', ');
|
|
|
|
// Format question content with improved styling
|
|
const formattedQuestionContent = processQuestionContent(question.content);
|
|
|
|
// Create formatted content with minimal layout
|
|
return `
|
|
<div class="d-flex flex-column" style="height: 100%;">
|
|
<div class="question-header">
|
|
|
|
<div class="mb-3">
|
|
<strong>Solve this question on instance:</strong> <span class="inline-code">ssh ${machineHostname}</span></span>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<strong>Namespace:</strong> <span class="text-primary">${namespace}</span>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<strong>Concepts:</strong> <span class="text-primary">${conceptsString}</span>
|
|
</div>
|
|
|
|
<hr class="my-3">
|
|
</div>
|
|
|
|
<div class="question-body">
|
|
${formattedQuestionContent}
|
|
</div>
|
|
|
|
<div class="action-buttons-container mt-auto">
|
|
<div class="d-flex justify-content-between py-2">
|
|
<button class="btn ${question.flagged ? 'btn-warning' : 'btn-outline-warning'}" id="flagQuestionBtn">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-flag${question.flagged ? '-fill' : ''} me-2" viewBox="0 0 16 16">
|
|
<path d="M14.778.085A.5.5 0 0 1 15 .5V8a.5.5 0 0 1-.314.464L14.5 8l.186.464-.003.001-.006.003-.023.009a12.435 12.435 0 0 1-.397.15c-.264.095-.631.223-1.047.35-.816.252-1.879.523-2.71.523-.847 0-1.548-.28-2.158-.525l-.028-.01C7.68 8.71 7.14 8.5 6.5 8.5c-.7 0-1.638.23-2.437.477A19.626 19.626 0 0 0 3 9.342V15.5a.5.5 0 0 1-1 0V.5a.5.5 0 0 1 1 0v.282c.226-.079.496-.17.79-.26C4.606.272 5.67 0 6.5 0c.84 0 1.524.277 2.121.519l.043.018C9.286.788 9.828 1 10.5 1c.7 0 1.638-.23 2.437-.477a19.587 19.587 0 0 0 1.349-.476l.019-.007.004-.002h.001"/>
|
|
</svg>
|
|
${question.flagged ? 'Flagged' : 'Flag for review'}
|
|
</button>
|
|
<button class="btn btn-success" id="nextQuestionBtn">
|
|
Satisfied with answer
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-right ms-2" viewBox="0 0 16 16">
|
|
<path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} catch (error) {
|
|
console.error('Error generating question content:', error);
|
|
return '<div class="alert alert-danger">Error displaying question content. Please try refreshing the page.</div>';
|
|
}
|
|
}
|
|
|
|
// Transform API response to question objects
|
|
function transformQuestionsFromApi(data) {
|
|
if (data.questions && Array.isArray(data.questions)) {
|
|
// Transform the questions to match our expected format
|
|
return data.questions.map(q => ({
|
|
id: q.id,
|
|
content: q.question || '', // Map 'question' field to 'content'
|
|
title: `Question ${q.id}`, // Create a title from the ID
|
|
originalData: q, // Keep original data for reference if needed
|
|
flagged: false // Add flagged status property
|
|
}));
|
|
}
|
|
return [];
|
|
}
|
|
|
|
// Update question dropdown
|
|
function updateQuestionDropdown(questionsArray, dropdownMenu, currentId, onQuestionSelect) {
|
|
// Clear existing dropdown items
|
|
dropdownMenu.innerHTML = '';
|
|
|
|
// Add items for each question
|
|
questionsArray.forEach((question) => {
|
|
const li = document.createElement('li');
|
|
const a = document.createElement('a');
|
|
a.className = 'dropdown-item';
|
|
a.href = '#';
|
|
a.dataset.question = question.id;
|
|
a.textContent = `Question ${question.id}`;
|
|
|
|
// Add flag icon if question is flagged
|
|
if (question.flagged) {
|
|
const flagIcon = document.createElement('span');
|
|
flagIcon.className = 'flag-icon ms-2';
|
|
flagIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-flag-fill text-warning" viewBox="0 0 16 16"><path d="M14.778.085A.5.5 0 0 1 15 .5V8a.5.5 0 0 1-.314.464L14.5 8l.186.464-.003.001-.006.003-.023.009a12.435 12.435 0 0 1-.397.15c-.264.095-.631.223-1.047.35-.816.252-1.879.523-2.71.523-.847 0-1.548-.28-2.158-.525l-.028-.01C7.68 8.71 7.14 8.5 6.5 8.5c-.7 0-1.638.23-2.437.477A19.626 19.626 0 0 0 3 9.342V15.5a.5.5 0 0 1-1 0V.5a.5.5 0 0 1 1 0v.282c.226-.079.496-.17.79-.26C4.606.272 5.67 0 6.5 0c.84 0 1.524.277 2.121.519l.043.018C9.286.788 9.828 1 10.5 1c.7 0 1.638-.23 2.437-.477a19.587 19.587 0 0 0 1.349-.476l.019-.007.004-.002h.001"/></svg>';
|
|
a.appendChild(flagIcon);
|
|
}
|
|
|
|
// Add click event
|
|
a.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const clickedQuestionId = this.dataset.question;
|
|
if (onQuestionSelect) {
|
|
onQuestionSelect(clickedQuestionId);
|
|
}
|
|
});
|
|
|
|
li.appendChild(a);
|
|
dropdownMenu.appendChild(li);
|
|
});
|
|
}
|
|
|
|
export {
|
|
processQuestionContent,
|
|
generateQuestionContent,
|
|
transformQuestionsFromApi,
|
|
updateQuestionDropdown
|
|
};
|