let editors = {};
let currentTab = 0;
let tabs = [];
let modules = {};
let currentTheme = 'dark';
// Initialize modules
const moduleData = {
'auth': {
name: 'Authentication Module',
description: 'Handles user authentication, sessions, and security',
version: '2.1.4',
language: 'php',
content: `userService = new UserService();
}
public function login($credentials) {
if ($this->validateCredentials($credentials)) {
$user = $this->userService->authenticate($credentials);
if ($user) {
return $this->createSession($user);
}
}
throw new AuthenticationException("Invalid credentials");
}
private function validateCredentials($credentials) {
return isset($credentials['email']) && isset($credentials['password']);
}
private function createSession($user) {
$token = JWT::encode([
'user_id' => $user->id,
'exp' => time() + 3600
], $_ENV['JWT_SECRET']);
return [
'token' => $token,
'user' => $user->toArray()
];
}
}`
},
'api': {
name: 'API Module',
description: 'RESTful API endpoints and middleware',
version: '1.5.2',
language: 'javascript',
content: `const express = require('express');
const router = express.Router();
const { authenticate, authorize } = require('../middleware/auth');
// Apply authentication middleware to all routes
router.use(authenticate);
// User endpoints
router.get('/users', authorize('admin'), async (req, res) => {
try {
const users = await User.find().select('-password');
res.json({
success: true,
data: users,
count: users.length
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message
});
}
});
router.post('/users', authorize('admin'), async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json({
success: true,
data: user
});
} catch (error) {
res.status(400).json({
success: false,
message: error.message
});
}
});
module.exports = router;`
},
'frontend': {
name: 'Frontend Module',
description: 'React components and UI elements',
version: '3.0.1',
language: 'htmlmixed',
content: `
Dashboard
Analytics
View detailed analytics and reports
Users
Manage user accounts and permissions
Settings
Configure application settings
`
}
};
// Version history storage
const versionHistory = {
'auth': [
{ version: '2.1.4', date: '2024-01-15', changes: 'Fixed session timeout issue' },
{ version: '2.1.3', date: '2024-01-10', changes: 'Improved password hashing' },
{ version: '2.1.2', date: '2024-01-05', changes: 'Added multi-factor authentication' }
],
'api': [
{ version: '1.5.2', date: '2024-01-14', changes: 'Optimized database queries' },
{ version: '1.5.1', date: '2024-01-08', changes: 'Fixed CORS issues' },
{ version: '1.5.0', date: '2024-01-01', changes: 'Added rate limiting' }
],
'frontend': [
{ version: '3.0.1', date: '2024-01-16', changes: 'Fixed responsive design bugs' },
{ version: '3.0.0', date: '2024-01-01', changes: 'Complete UI redesign with Tailwind' }
]
};
// Initialize application
document.addEventListener('DOMContentLoaded', function() {
initializeModules();
createDefaultTabs();
renderModuleList();
// Set initial theme
document.documentElement.setAttribute('data-theme', currentTheme);
});
function initializeModules() {
for (const [key, module] of Object.entries(moduleData)) {
modules[key] = { ...module, id: key };
}
}
function createDefaultTabs() {
addTab('auth', 'auth.php');
addTab('api', 'api.js');
addTab('frontend', 'index.html');
}
function addTab(moduleId, filename) {
const tabId = `tab-${Date.now()}`;
const module = modules[moduleId];
if (!module) return;
tabs.push({
id: tabId,
moduleId: moduleId,
filename: filename,
module: module
});
// Create tab UI
const tabContainer = document.getElementById('tabContainer');
const tabElement = document.createElement('div');
tabElement.className = `tab-item flex items-center gap-2 px-4 py-3 bg-gray-700 hover:bg-gray-600 cursor-pointer transition-colors border-r border-gray-600 ${tabs.length === 1 ? 'tab-active' : ''}`;
tabElement.id = tabId;
tabElement.onclick = () => switchTab(tabs.length - 1);
const extension = filename.split('.').pop().toLowerCase();
const iconMap = {
'php': '',
'js': '',
'html': '',
'css': ''
};
tabElement.innerHTML = `
${iconMap[extension] || ''}
${filename}
`;
tabContainer.appendChild(tabElement);
// Create editor
createEditor(tabId, module.content, module.language);
// Switch to new tab
switchTab(tabs.length - 1);
feather.replace();
}
function createEditor(tabId, content, mode) {
const container = document.getElementById('editorContainer');
const editorDiv = document.createElement('div');
editorDiv.id = `editor-${tabId}`;
editorDiv.className = 'h-full hidden';
editorDiv.innerHTML = ``;
container.appendChild(editorDiv);
const editor = CodeMirror.fromTextArea(document.getElementById(`textarea-${tabId}`), {
value: content,
mode: mode,
theme: currentTheme === 'dark' ? 'monokai' : 'default',
lineNumbers: true,
lineWrapping: true,
autoCloseBrackets: true,
matchBrackets: true,
indentUnit: 4,
tabSize: 4,
indentWithTabs: false
});
editor.setValue(content);
// Update cursor position
editor.on('cursorActivity', function() {
const cursor = editor.getCursor();
document.getElementById('cursorPosition').textContent = `Ln ${cursor.line + 1}, Col ${cursor.ch + 1}`;
});
// Update file info
editor.on('change', function() {
const tab = tabs.find(t => t.id === tabId);
if (tab) {
document.getElementById('fileInfo').textContent = `${tab.filename} • Modified`;
}
});
editors[tabId] = editor;
}
function switchTab(index) {
// Hide all editors
tabs.forEach(tab => {
const editorDiv = document.getElementById(`editor-${tab.id}`);
if (editorDiv) editorDiv.classList.add('hidden');
const tabElement = document.getElementById(tab.id);
if (tabElement) tabElement.classList.remove('tab-active');
});
// Show selected editor
const selectedTab = tabs[index];
const editorDiv = document.getElementById(`editor-${selectedTab.id}`);
if (editorDiv) {
editorDiv.classList.remove('hidden');
// Refresh editor to fix display issues
setTimeout(() => {
editors[selectedTab.id].refresh();
}, 10);
}
const tabElement = document.getElementById(selectedTab.id);
if (tabElement) tabElement.classList.add('tab-active');
currentTab = index;
// Update status bar
document.getElementById('fileInfo').textContent = selectedTab.filename;
document.getElementById('language').textContent = selectedTab.module.language.toUpperCase();
document.getElementById('gitBranch').textContent = selectedTab.moduleId;
}
function closeTab(tabId) {
const index = tabs.findIndex(t => t.id === tabId);
if (index === -1) return;
// Remove tab
tabs.splice(index, 1);
// Remove UI elements
const tabElement = document.getElementById(tabId);
if (tabElement) tabElement.remove();
const editorDiv = document.getElementById(`editor-${tabId}`);
if (editorDiv) editorDiv.remove();
delete editors[tabId];
// Switch to another tab if available
if (tabs.length > 0) {
switchTab(Math.min(currentTab, tabs.length - 1));
}
}
function addNewTab() {
// Create a simple file selection dialog
const moduleKeys = Object.keys(modules);
const moduleId = moduleKeys[Math.floor(Math.random() * moduleKeys.length)];
const module = modules[moduleId];
const extension = module.language === 'htmlmixed' ? 'html' : module.language;
const filename = `new-${Date.now()}.${extension}`;
addTab(moduleId, filename);
}
function renderModuleList() {
const moduleList = document.getElementById('moduleList');
moduleList.innerHTML = '';
Object.values(modules).forEach(module => {
const moduleElement = document.createElement('div');
moduleElement.className = 'module-item bg-gray-700 rounded-lg p-4 cursor-pointer';
moduleElement.innerHTML = `
${getModuleIcon(module.language)}
${module.name}
${module.description}
v${module.version}
${module.language}
`;
moduleElement.onclick = (e) => {
if (e.target.closest('button')) return;
openModuleTab(module.id);
};
moduleList.appendChild(moduleElement);
});
feather.replace();
}
function getModuleIcon(language) {
const icons = {
'php': '',
'javascript': '',
'htmlmixed': ''
};
return icons[language] || '';
}
function openModuleTab(moduleId) {
const module = modules[moduleId];
if (!module) return;
// Check if tab already exists
const existingTab = tabs.find(t => t.moduleId === moduleId);
if (existingTab) {
const index = tabs.findIndex(t => t.id === existingTab.id);
switchTab(index);
return;
}
const extension = module.language === 'htmlmixed' ? 'html' : module.language;
const filename = `${moduleId}.${extension}`;
addTab(moduleId, filename);
}
function showVersionHistory(moduleId) {
const modal = document.getElementById('versionModal');
const versionList = document.getElementById('versionList');
const history = versionHistory[moduleId] || [];
versionList.innerHTML = history.map(v => `
`).join('');
modal.classList.remove('hidden');
modal.dataset.moduleId = moduleId;
}
function closeVersionModal() {
document.getElementById('versionModal').classList.add('hidden');
}
function createPatch() {
const modal = document.getElementById('versionModal');
const moduleId = modal.dataset.moduleId;
if (moduleId) {
alert(`Creating patch for ${modules[moduleId]?.name || 'Module'}...`);
}
closeVersionModal();
}
function showDiffView(moduleId) {
const module = modules[moduleId];
if (!module) return;
// Create a diff view tab
const tabId = `diff-${Date.now()}`;
const tabContainer = document.getElementById('tabContainer');
const tabElement = document.createElement('div');
tabElement.className = 'tab-item flex items-center gap-2 px-4 py-3 bg-gray-700 hover:bg-gray-600 cursor-pointer transition-colors border-r border-gray-600';
tabElement.id = tabId;
tabElement.innerHTML = `
${moduleId} - Diff
`;
tabContainer.appendChild(tabElement);
tabs.push({
id: tabId,
moduleId: moduleId,
filename: `${moduleId} - Diff`,
module: module,
isDiff: true
});
// Create diff view
const container = document.getElementById('editorContainer');
const editorDiv = document.createElement('div');
editorDiv.id = `editor-${tabId}`;
editorDiv.className = 'h-full hidden';
editorDiv.innerHTML = `
`;
container.appendChild(editorDiv);
// Initialize diff editors
const leftEditor = CodeMirror.fromTextArea(document.getElementById(`diff-left-${tabId}`), {
mode: module.language,
theme: currentTheme === 'dark' ? 'monokai' : 'default',
lineNumbers: true,
readOnly: true
});
const rightEditor = CodeMirror.fromTextArea(document.getElementById(`diff-right-${tabId}`), {
mode: module.language,
theme: currentTheme === 'dark' ? 'monokai' : 'default',
lineNumbers: true,
readOnly: true
});
leftEditor.setValue(module.content);
rightEditor.setValue(module.content.substring(0, Math.floor(module.content.length * 0.7)));
editors[tabId] = { left: leftEditor, right: rightEditor, isDiff: true };
switchTab(tabs.length - 1);
feather.replace();
}
function changeModuleVersion(moduleId) {
const module = modules[moduleId];
if (!module) return;
const versions = versionHistory[moduleId] || [];
if (versions.length === 0) {
alert('No previous versions available');
return;
}
const newVersion = versions[0];
module.version = newVersion.version;
renderModuleList();
alert(`Module updated to version ${newVersion.version}`);
}
function toggleTheme() {
currentTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', currentTheme);
const themeIcon = document.querySelector('.theme-icon');
themeIcon.setAttribute('data-feather', currentTheme === 'dark' ? 'sun' : 'moon');
feather.replace();
// Update all editor themes
Object.values(editors).forEach(editor => {
if (editor.isDiff) {
if (editor.left) editor.left.setOption('theme', currentTheme === 'dark' ? 'monokai' : 'default');
if (editor.right) editor.right.setOption('theme', currentTheme === 'dark' ? 'monokai' : 'default');
} else {
editor.setOption('theme', currentTheme === 'dark' ? 'monokai' : 'default');
}
});
}