Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 86 additions & 2 deletions web/virtual_lab/static/virtual_lab/js/code_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,99 @@ function getCookie(name) {
return match ? decodeURIComponent(match[2]) : null;
}

// Language configuration for Ace editor
const languageConfig = {
python: {
mode: "ace/mode/python",
sample: 'print("Hello, World!")'
},
javascript: {
mode: "ace/mode/javascript",
sample: 'console.log("Hello, World!");'
},
c: {
mode: "ace/mode/c_cpp",
sample: '#include <stdio.h>\n\nint main() {\n printf("Hello, World!\\n");\n return 0;\n}'
},
cpp: {
mode: "ace/mode/c_cpp",
sample: '#include <iostream>\nusing namespace std;\n\nint main() {\n cout << "Hello, World!" << endl;\n return 0;\n}'
}
};

// Wait for DOM to be ready
document.addEventListener('DOMContentLoaded', function() {

// Bootstrap Ace
const editor = ace.edit("editor");
editor.setTheme("ace/theme/github");
editor.session.setMode("ace/mode/python");
editor.setOptions({ fontSize: "14px", showPrintMargin: false });
editor.setOptions({
fontSize: "14px",
showPrintMargin: false,
wrap: true
});

const runBtn = document.getElementById("run-btn");
const outputEl = document.getElementById("output");
const stdinEl = document.getElementById("stdin-input");
const langSel = document.getElementById("language-select");

// Track the currently active language
let currentLanguage = "python";

// Helper to detect if the editor contains unsaved (non-sample) code
function hasUnsavedChanges() {
const currentCode = editor.getValue();
const normalizedCurrent = currentCode.trimEnd();

// Empty editor is treated as having no unsaved changes
if (!normalizedCurrent) {
return false;
}

// If the current code matches any sample (ignoring trailing whitespace), we treat it as not modified
const matchesAnySample = Object.values(languageConfig).some((config) => {
return config.sample.trimEnd() === normalizedCurrent;
});

return !matchesAnySample;
}

// Function to update editor mode and sample code based on selected language
function updateEditorLanguage(language) {
const config = languageConfig[language];
if (config) {
// Only overwrite the editor contents if there are no unsaved changes,
// or if the user explicitly confirms discarding their current code.
if (hasUnsavedChanges()) {
const confirmDiscard = window.confirm(
"You have code in the editor that differs from the default samples. " +
"Switching languages will replace it with example code for the selected language. " +
"Do you want to discard your current code?"
);

if (!confirmDiscard) {
// Revert the dropdown to the previously active language
langSel.value = currentLanguage;
return;
}
}

currentLanguage = language;
editor.session.setMode(config.mode);
editor.setValue(config.sample, -1); // -1 moves cursor to start
}
}

// Language selector change handler
langSel.addEventListener("change", (e) => {
const selectedLanguage = e.target.value;
updateEditorLanguage(selectedLanguage);
});

// Initialize with Python sample code
updateEditorLanguage("python");

runBtn.addEventListener("click", () => {
const code = editor.getValue();
const stdin = stdinEl.value;
Expand Down Expand Up @@ -51,3 +133,5 @@ runBtn.addEventListener("click", () => {
runBtn.disabled = false;
});
});

}); // End DOMContentLoaded
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{# templates/virtual_lab/code_editor/code_editor.html #}
{% extends 'virtual_lab/layout.html' %}
{% extends "virtual_lab/layout.html" %}

{% load static %}

Expand Down Expand Up @@ -38,7 +38,7 @@
<div class="max-w-4xl mx-auto py-8">
<h1 class="text-2xl font-bold mb-4 dark:text-gray-100">Interactive Code Editor</h1>
<!-- Editor -->
<div id="editor">print("Hello, world!")</div>
<div id="editor"></div>
<!-- Language selector -->
<div class="mt-4 mb-2">
<label for="language-select" class="dark:text-gray-300">Language:</label>
Expand Down
Loading