Zurück
Download
Lade alle benötigten Dateien herunter und integriere Rizo CMS in deine Website.
Urheberrechtlich geschützt
Diese Software ist urheberrechtlich geschützt. Weiterverkauf, Weitergabe und Redistribution sind nicht gestattet. Durch den Download akzeptierst du die Lizenzbestimmungen.
Dateistruktur
deine-website/ ├── index.html ← Deine HTML-Seite ├── Rizo-CMS.js ← Haupt-Script ├── config.php ← Konfiguration & Login └── auth.php ← Authentifizierung
Rizo-CMS.js
/**
* ============================================================
* Rizo CMS - PROPRIETÄRE SOFTWARE
* ============================================================
* Copyright (c) 2025 Rizo. Alle Rechte vorbehalten.
*
* LIZENZHINWEIS:
* Diese Software ist urheberrechtlich geschützt. Die Nutzung
* ist nur für den persönlichen/geschäftlichen Gebrauch auf
* eigenen Webseiten gestattet.
*
* VERBOTEN IST:
* - Weiterverkauf oder kommerzielle Weitergabe
* - Weitergabe an Dritte (kostenpflichtig)
* - Modifikation und Redistribution
* - Entfernen dieses Copyright-Hinweises
*
* Bei Verstößen behalten wir uns rechtliche Schritte vor.
* Kontakt: [hello@rizocms.com]
* ============================================================
*/
/**
* Rizo CMS v1.0.1
* Ein leichtgewichtiges Rizo-CMS für statische HTML-Seiten
* MIT SEO SCORE & PHP AUTHENTIFIZIERUNG
*
* Verwendung:
* 1. config.php und auth.php im selben Ordner platzieren
* 2. Script in HTML-Seite einbinden: <script src="Rizo-CMS.js"></script>
* 3. Elemente mit data-editable="name" markieren
* 4. ALT+E drücken zum Editieren (Login erforderlich)
*/
(function() {
'use strict';
// ===== KONFIGURATION =====
const CONFIG = {
AUTH_ENDPOINT: 'auth.php',
STORAGE_KEY: 'Rizo-cms-data',
SHORTCUT_KEY: 'KeyE',
HIGHLIGHT_COLOR: '#3b82f6',
SEO_ENABLED: true
};
// ===== STATE =====
let isEditMode = false;
let isLoggedIn = false;
let currentElement = null;
let csrfToken = null;
// ===== STYLES =====
const STYLES = `
.icms-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 999998;
display: flex;
align-items: center;
justify-content: center;
}
.icms-modal {
background: #1a1a2e;
border-radius: 12px;
padding: 32px;
max-width: 500px;
width: 90%;
box-shadow: 0 25px 50px rgba(0,0,0,0.5);
max-height: 80vh;
overflow-y: auto;
}
.icms-modal h2 {
color: #fff;
margin: 0 0 8px 0;
font-size: 24px;
}
.icms-modal p {
color: #888;
margin: 0 0 24px 0;
font-size: 14px;
}
.icms-input {
width: 100%;
padding: 12px 16px;
border: 1px solid #333;
border-radius: 8px;
background: #0f0f1a;
color: #fff;
font-size: 14px;
margin-bottom: 12px;
box-sizing: border-box;
}
.icms-input:focus {
outline: none;
border-color: ${CONFIG.HIGHLIGHT_COLOR};
}
.icms-btn {
width: 100%;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.icms-btn-primary {
background: ${CONFIG.HIGHLIGHT_COLOR};
color: #fff;
}
.icms-btn-primary:hover {
opacity: 0.9;
}
.icms-btn-secondary {
background: #2a2a3e;
color: #fff;
margin-top: 8px;
}
.icms-btn-secondary:hover {
background: #3a3a4e;
}
.icms-error {
color: #ef4444;
font-size: 12px;
margin-top: 8px;
}
.icms-image-preview {
width: 100%;
max-height: 300px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 16px;
border: 2px solid #333;
}
.icms-file-input-wrapper {
position: relative;
margin-bottom: 16px;
}
.icms-file-input {
width: 100%;
padding: 12px;
border: 2px dashed #333;
border-radius: 8px;
background: #0f0f1a;
color: #888;
cursor: pointer;
text-align: center;
transition: all 0.2s;
}
.icms-file-input:hover {
border-color: ${CONFIG.HIGHLIGHT_COLOR};
color: #fff;
}
.icms-toolbar {
position: fixed;
top: 20px;
right: 20px;
background: #1a1a2e;
border-radius: 12px;
padding: 12px;
display: flex;
gap: 8px;
z-index: 999999;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}
.icms-toolbar button {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
background: #2a2a3e;
color: #fff;
}
.icms-toolbar button:hover {
background: #3a3a4e;
}
.icms-toolbar button.active {
background: ${CONFIG.HIGHLIGHT_COLOR};
}
.icms-editable {
outline: 2px dashed ${CONFIG.HIGHLIGHT_COLOR}44;
outline-offset: 4px;
transition: all 0.2s;
}
.icms-editable:hover {
outline-color: ${CONFIG.HIGHLIGHT_COLOR};
cursor: pointer;
}
.icms-editing {
outline: 2px solid ${CONFIG.HIGHLIGHT_COLOR};
outline-offset: 4px;
}
.icms-seo-panel {
position: fixed;
top: 80px;
right: 20px;
width: 320px;
background: #1a1a2e;
border-radius: 12px;
padding: 20px;
z-index: 999998;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
max-height: 70vh;
overflow-y: auto;
}
.icms-seo-panel h3 {
color: #fff;
margin: 0 0 16px 0;
font-size: 16px;
display: flex;
align-items: center;
gap: 8px;
}
.icms-seo-score {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: #0f0f1a;
border-radius: 8px;
margin-bottom: 12px;
}
.icms-score-circle {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 16px;
color: #fff;
}
.icms-score-good { background: #22c55e; }
.icms-score-medium { background: #f59e0b; }
.icms-score-bad { background: #ef4444; }
.icms-seo-item {
padding: 12px;
background: #0f0f1a;
border-radius: 8px;
margin-bottom: 8px;
}
.icms-seo-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.icms-seo-item-title {
color: #fff;
font-size: 13px;
font-weight: 500;
}
.icms-seo-item-value {
color: #888;
font-size: 12px;
}
.icms-seo-bar {
height: 4px;
background: #333;
border-radius: 2px;
overflow: hidden;
}
.icms-seo-bar-fill {
height: 100%;
border-radius: 2px;
transition: width 0.3s;
}
.icms-copyright {
font-size: 10px;
color: #666;
text-align: center;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid #333;
}
`;
// ===== AUTH FUNKTIONEN =====
async function checkAuth() {
try {
const res = await fetch(CONFIG.AUTH_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'check' })
});
const data = await res.json();
isLoggedIn = data.logged_in;
csrfToken = data.csrf_token;
return isLoggedIn;
} catch (e) {
console.warn('Auth check failed, running in standalone mode');
isLoggedIn = true;
return true;
}
}
async function login(username, password) {
try {
const res = await fetch(CONFIG.AUTH_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'login', username, password })
});
const data = await res.json();
if (data.success) {
isLoggedIn = true;
csrfToken = data.csrf_token;
}
return data;
} catch (e) {
return { success: false, message: 'Verbindungsfehler' };
}
}
async function logout() {
try {
await fetch(CONFIG.AUTH_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'logout' })
});
} catch (e) {}
isLoggedIn = false;
csrfToken = null;
exitEditMode();
}
// ===== UI FUNKTIONEN =====
function injectStyles() {
const style = document.createElement('style');
style.textContent = STYLES;
document.head.appendChild(style);
}
function showLoginModal() {
const overlay = document.createElement('div');
overlay.className = 'icms-overlay';
overlay.innerHTML = `
<div class="icms-modal">
<h2>🔐 Rizo CMS</h2>
<p>Melde dich an, um Inhalte zu bearbeiten</p>
<input type="text" class="icms-input" id="icms-username" placeholder="Benutzername">
<input type="password" class="icms-input" id="icms-password" placeholder="Passwort">
<button class="icms-btn icms-btn-primary" id="icms-login-btn">Anmelden</button>
<div class="icms-error" id="icms-error" style="display:none"></div>
<div class="icms-copyright">© 2025 Rizo CMS - Urheberrechtlich geschützt</div>
</div>
`;
document.body.appendChild(overlay);
const loginBtn = document.getElementById('icms-login-btn');
const usernameInput = document.getElementById('icms-username');
const passwordInput = document.getElementById('icms-password');
const errorDiv = document.getElementById('icms-error');
async function doLogin() {
const result = await login(usernameInput.value, passwordInput.value);
if (result.success) {
overlay.remove();
enterEditMode();
} else {
errorDiv.textContent = result.message;
errorDiv.style.display = 'block';
}
}
loginBtn.addEventListener('click', doLogin);
passwordInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') doLogin();
});
overlay.addEventListener('click', (e) => {
if (e.target === overlay) overlay.remove();
});
usernameInput.focus();
}
function showImageUploadModal(element) {
const overlay = document.createElement('div');
overlay.className = 'icms-overlay';
const currentSrc = element.src || element.style.backgroundImage.replace(/url$$['"](.+)['"]$$/, '$1');
let newImageData = null;
overlay.innerHTML = `
<div class="icms-modal">
<h2>🖼️ Bild ändern</h2>
<p>Aktuelles Bild oder neues Bild hochladen</p>
<div style="margin-bottom: 16px;">
<p style="font-size: 12px; color: #888; margin-bottom: 8px;">Aktuelles Bild:</p>
<img src="${currentSrc}" class="icms-image-preview" alt="Current" />
</div>
<div class="icms-file-input-wrapper">
<label for="icms-file-input" class="icms-file-input">
📁 Neues Bild auswählen
</label>
<input type="file" id="icms-file-input" accept="image/*" style="display: none;" />
</div>
<div id="icms-new-preview" style="display: none; margin-bottom: 16px;">
<p style="font-size: 12px; color: #888; margin-bottom: 8px;">Neues Bild:</p>
<img id="icms-new-image" class="icms-image-preview" alt="New" />
</div>
<button class="icms-btn icms-btn-primary" id="icms-save-image" disabled>Bild speichern</button>
<button class="icms-btn icms-btn-secondary" id="icms-cancel-image">Abbrechen</button>
<div class="icms-copyright">© 2025 Rizo CMS</div>
</div>
`;
document.body.appendChild(overlay);
const fileInput = document.getElementById('icms-file-input');
const fileLabel = fileInput.previousElementSibling;
const newPreview = document.getElementById('icms-new-preview');
const newImage = document.getElementById('icms-new-image');
const saveBtn = document.getElementById('icms-save-image');
const cancelBtn = document.getElementById('icms-cancel-image');
fileLabel.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
newImageData = event.target.result;
newImage.src = newImageData;
newPreview.style.display = 'block';
saveBtn.disabled = false;
fileLabel.textContent = '✓ ' + file.name;
fileLabel.style.borderColor = CONFIG.HIGHLIGHT_COLOR;
fileLabel.style.color = '#fff';
};
reader.readAsDataURL(file);
}
});
saveBtn.addEventListener('click', () => {
if (newImageData) {
if (element.tagName === 'IMG') {
element.src = newImageData;
} else {
element.style.backgroundImage = `url('${newImageData}')`;
}
const key = element.getAttribute('data-editable');
const data = JSON.parse(localStorage.getItem(CONFIG.STORAGE_KEY) || '{}');
data[key] = { type: 'image', value: newImageData };
localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(data));
overlay.remove();
}
});
cancelBtn.addEventListener('click', () => overlay.remove());
overlay.addEventListener('click', (e) => {
if (e.target === overlay) overlay.remove();
});
}
function createToolbar() {
const toolbar = document.createElement('div');
toolbar.className = 'icms-toolbar';
toolbar.id = 'icms-toolbar';
toolbar.innerHTML = `
<button id="icms-btn-save">💾 Speichern</button>
<button id="icms-btn-export">📄 Export</button>
<button id="icms-btn-seo">📊 SEO</button>
<button id="icms-btn-reset">🔄 Reset</button>
<button id="icms-btn-logout">🚪 Logout</button>
<button id="icms-btn-exit">✕</button>
`;
document.body.appendChild(toolbar);
document.getElementById('icms-btn-save').addEventListener('click', saveChanges);
document.getElementById('icms-btn-export').addEventListener('click', exportHTML);
document.getElementById('icms-btn-seo').addEventListener('click', toggleSEOPanel);
document.getElementById('icms-btn-reset').addEventListener('click', resetChanges);
document.getElementById('icms-btn-logout').addEventListener('click', logout);
document.getElementById('icms-btn-exit').addEventListener('click', exitEditMode);
}
// ===== SEO FUNKTIONEN =====
function calculateReadability(text) {
const words = text.split(/\s+/).filter(w => w.length > 0);
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
const syllables = words.reduce((acc, word) => {
return acc + (word.match(/[aeiouyäöü]/gi) || []).length;
}, 0);
if (words.length === 0 || sentences.length === 0) return 0;
const avgWordsPerSentence = words.length / sentences.length;
const avgSyllablesPerWord = syllables / words.length;
// Flesch-Reading-Ease (German adaptation)
const score = 180 - avgWordsPerSentence - (58.5 * avgSyllablesPerWord);
return Math.max(0, Math.min(100, score));
}
function getKeywords(text) {
const stopWords = ['der', 'die', 'das', 'und', 'ist', 'in', 'zu', 'den', 'mit', 'von', 'für', 'auf', 'ein', 'eine', 'einer', 'eines', 'einem', 'einen', 'dem', 'des', 'im', 'am', 'zum', 'zur', 'als', 'sich', 'bei', 'nach', 'aus', 'um', 'oder', 'auch', 'nicht', 'werden', 'wird', 'kann', 'sind', 'hat', 'haben'];
const words = text.toLowerCase().match(/[a-zäöüß]+/gi) || [];
const filtered = words.filter(w => w.length > 3 && !stopWords.includes(w));
const freq = {};
filtered.forEach(w => freq[w] = (freq[w] || 0) + 1);
return Object.entries(freq).sort((a, b) => b[1] - a[1]).slice(0, 5).map(e => e[0]);
}
function analyzeSEO() {
const title = document.title || '';
const description = document.querySelector('meta[name="description"]')?.content || '';
const h1 = document.querySelector('h1')?.textContent || '';
const bodyText = document.body.textContent;
const checks = {
title: {
label: 'Title',
value: title.length,
min: 30,
max: 60,
score: title.length >= 30 && title.length <= 60 ? 100 : Math.max(0, 100 - Math.abs(45 - title.length) * 2)
},
description: {
label: 'Meta Description',
value: description.length,
min: 120,
max: 160,
score: description.length >= 120 && description.length <= 160 ? 100 : Math.max(0, 100 - Math.abs(140 - description.length))
},
h1: {
label: 'H1 Überschrift',
value: h1.length,
min: 20,
max: 70,
score: h1.length >= 20 && h1.length <= 70 ? 100 : Math.max(0, 100 - Math.abs(45 - h1.length) * 2)
},
readability: {
label: 'Lesbarkeit',
value: Math.round(calculateReadability(bodyText)),
min: 60,
max: 100,
score: calculateReadability(bodyText)
},
keywords: {
label: 'Keywords',
value: getKeywords(bodyText).join(', '),
score: getKeywords(bodyText).length >= 3 ? 100 : getKeywords(bodyText).length * 33
}
};
const totalScore = Math.round(
Object.values(checks).reduce((acc, check) => acc + check.score, 0) / Object.keys(checks).length
);
return { checks, totalScore };
}
function createSEOPanel() {
const existing = document.getElementById('icms-seo-panel');
if (existing) {
existing.remove();
return;
}
const { checks, totalScore } = analyzeSEO();
const panel = document.createElement('div');
panel.className = 'icms-seo-panel';
panel.id = 'icms-seo-panel';
const scoreClass = totalScore >= 80 ? 'icms-score-good' : totalScore >= 50 ? 'icms-score-medium' : 'icms-score-bad';
let html = `
<h3>📊 SEO Score</h3>
<div class="icms-seo-score">
<div class="icms-score-circle ${scoreClass}">${totalScore}</div>
<div>
<div style="color: #fff; font-weight: 600; margin-bottom: 4px;">
${totalScore >= 80 ? 'Sehr gut!' : totalScore >= 50 ? 'OK' : 'Verbesserung nötig'}
</div>
<div style="color: #888; font-size: 12px;">Gesamt-Score</div>
</div>
</div>
`;
for (const [key, check] of Object.entries(checks)) {
const percent = Math.min(100, check.score);
const color = check.score >= 80 ? '#22c55e' : check.score >= 50 ? '#f59e0b' : '#ef4444';
html += `
<div class="icms-seo-item">
<div class="icms-seo-item-header">
<span class="icms-seo-item-title">${check.label}</span>
<span class="icms-seo-item-value">${check.value}${key !== 'keywords' ? '/' + check.max : ''}</span>
</div>
<div class="icms-seo-bar">
<div class="icms-seo-bar-fill" style="width: ${percent}%; background: ${color};"></div>
</div>
</div>
`;
}
html += `<div class="icms-copyright">© 2025 Rizo CMS</div>`;
panel.innerHTML = html;
document.body.appendChild(panel);
}
function toggleSEOPanel() {
createSEOPanel();
}
// ===== STORAGE FUNKTIONEN =====
function saveChanges() {
const data = {};
const editables = document.querySelectorAll('[data-editable]');
editables.forEach(el => {
const key = el.getAttribute('data-editable');
const type = el.getAttribute('data-editable-type') || 'text';
if (type === 'image') {
const value = el.tagName === 'IMG' ? el.src : el.style.backgroundImage;
data[key] = { type, value };
} else {
data[key] = { type, value: el.innerHTML };
}
});
localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(data));
alert('✓ Änderungen gespeichert!');
}
function loadChanges() {
const data = JSON.parse(localStorage.getItem(CONFIG.STORAGE_KEY) || '{}');
Object.entries(data).forEach(([key, item]) => {
const el = document.querySelector(`[data-editable="${key}"]`);
if (el) {
if (item.type === 'image') {
if (el.tagName === 'IMG') {
el.src = item.value;
} else {
el.style.backgroundImage = item.value;
}
} else {
el.innerHTML = item.value;
}
}
});
}
function resetChanges() {
if (confirm('Alle Änderungen zurücksetzen?')) {
localStorage.removeItem(CONFIG.STORAGE_KEY);
location.reload();
}
}
// ===== EXPORT FUNKTIONEN =====
function exportHTML() {
const clone = document.documentElement.cloneNode(true);
// Remove CMS elements
clone.querySelectorAll('.icms-toolbar, .icms-seo-panel, .icms-overlay').forEach(el => el.remove());
clone.querySelectorAll('[data-editable]').forEach(el => {
el.classList.remove('icms-editable', 'icms-editing');
el.removeAttribute('contenteditable');
});
const html = '<!DOCTYPE html>\n' + clone.outerHTML;
const blob = new Blob([html], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `exported-${Date.now()}.html`;
a.click();
URL.revokeObjectURL(url);
}
// ===== EDIT FUNKTIONEN =====
function enterEditMode() {
isEditMode = true;
createToolbar();
const editables = document.querySelectorAll('[data-editable]');
editables.forEach(el => {
el.classList.add('icms-editable');
el.addEventListener('click', handleElementClick);
});
loadChanges();
}
function exitEditMode() {
isEditMode = false;
const toolbar = document.getElementById('icms-toolbar');
if (toolbar) toolbar.remove();
const seoPanel = document.getElementById('icms-seo-panel');
if (seoPanel) seoPanel.remove();
const editables = document.querySelectorAll('[data-editable]');
editables.forEach(el => {
el.classList.remove('icms-editable', 'icms-editing');
el.contentEditable = 'false';
el.removeEventListener('click', handleElementClick);
});
currentElement = null;
}
function handleElementClick(e) {
e.preventDefault();
e.stopPropagation();
const element = e.currentTarget;
const editableType = element.getAttribute('data-editable-type');
// Handle image editing
if (editableType === 'image') {
showImageUploadModal(element);
return;
}
// Handle text editing
if (currentElement) {
currentElement.classList.remove('icms-editing');
currentElement.contentEditable = 'false';
}
currentElement = element;
currentElement.classList.add('icms-editing');
currentElement.contentEditable = 'true';
currentElement.focus();
}
// ===== INITIALIZATION =====
async function init() {
injectStyles();
// Keyboard shortcut
document.addEventListener('keydown', async (e) => {
if (e.altKey && e.code === CONFIG.SHORTCUT_KEY) {
e.preventDefault();
if (!isEditMode) {
const authed = await checkAuth();
if (!authed) {
showLoginModal();
} else {
enterEditMode();
}
} else {
exitEditMode();
}
}
});
}
// Start when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
Schnellstart
- Lade alle drei Dateien herunter
- Platziere sie im selben Ordner wie deine HTML-Datei
- Ändere Benutzername und Passwort in
config.php - Füge
data-editable="name"zu editierbaren Elementen hinzu - Füge
data-editable="name" data-editable-type="image"zu Bilder-Elementen hinzu (z.B. img-Tags oder div mit background-image) - Binde das Script ein:
<script src="Rizo-CMS.js"></script> - Drücke ALT + E zum Editieren
Konfigurierbare Features
SEO Analyzer
Live SEO-Score beim Bearbeiten
Bild-Upload
Bilder direkt hochladen
HTML Export
Bereinigte HTML-Datei exportieren
Auto-Save
Automatisches Speichern
Keyboard Shortcuts
ALT+E zum Aktivieren
CSRF Schutz
Sicherheit gegen Angriffe
