ソースを参照

Wysiwyg and translation fix

svalavuo 6 日 前
コミット
9c5988c35a
6 ファイル変更473 行追加12 行削除
  1. 5 2
      admin/edit.php
  2. 113 0
      css/wysiwyg.css
  3. 10 10
      includes/config.php
  4. 226 0
      js/wysiwyg.js
  5. 1 0
      languages/fi.php
  6. 118 0
      test_wysiwyg.html

+ 5 - 2
admin/edit.php

@@ -91,6 +91,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title><?php echo $pubId ? 'Edit' : 'Create'; ?> Publication - <?php echo SITE_TITLE; ?></title>
     <link rel="stylesheet" href="../css/style.css">
+    <link rel="stylesheet" href="../css/wysiwyg.css">
 </head>
 <body>
     <div class="admin-layout">
@@ -170,8 +171,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                 </div>
 
                 <div class="form-group">
-                    <label for="content">Content *</label>
-                    <textarea id="content" name="content" rows="20" required><?php echo htmlspecialchars($pub['content'] ?? ''); ?></textarea>
+                    <label for="content" class="wysiwyg-label">Content *</label>
+                    <textarea id="content" name="content" rows="20" required style="display: none;"><?php echo htmlspecialchars($pub['content'] ?? ''); ?></textarea>
+                    <div id="wysiwyg-editor" class="wysiwyg-editor"></div>
                 </div>
 
                 <div class="form-actions">
@@ -183,5 +185,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             </form>
         </main>
     </div>
+<script src="../js/wysiwyg.js"></script>
 </body>
 </html>

+ 113 - 0
css/wysiwyg.css

@@ -0,0 +1,113 @@
+/* WYSIWYG Editor Styles */
+
+.wysiwyg-container {
+    position: relative;
+}
+
+.wysiwyg-editor {
+    min-height: 400px;
+    border: 1px solid #d1d5db;
+    border-radius: 6px;
+    background-color: white;
+}
+
+.wysiwyg-toolbar {
+    border: 1px solid #d1d5db;
+    border-bottom: none;
+    border-radius: 6px 6px 0 0;
+    background-color: #f9fafb;
+    padding: 8px;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 4px;
+}
+
+.wysiwyg-btn {
+    padding: 6px 10px;
+    border: 1px solid #d1d5db;
+    border-radius: 4px;
+    background-color: white;
+    cursor: pointer;
+    font-size: 12px;
+    transition: all 0.2s;
+}
+
+.wysiwyg-btn:hover {
+    background-color: #f3f4f6;
+    border-color: #9ca3af;
+}
+
+.wysiwyg-btn.active {
+    background-color: #3b82f6;
+    color: white;
+    border-color: #3b82f6;
+}
+
+.wysiwyg-separator {
+    width: 1px;
+    height: 24px;
+    background-color: #d1d5db;
+    margin: 0 4px;
+}
+
+.wysiwyg-select {
+    padding: 4px 8px;
+    border: 1px solid #d1d5db;
+    border-radius: 4px;
+    background-color: white;
+    font-size: 12px;
+}
+
+.wysiwyg-content {
+    padding: 12px;
+    min-height: 350px;
+    font-family: inherit;
+    font-size: 14px;
+    line-height: 1.5;
+    border: none;
+    outline: none;
+    resize: vertical;
+}
+
+.wysiwyg-content:focus {
+    outline: 2px solid #3b82f6;
+    outline-offset: -2px;
+}
+
+/* Form integration */
+.publication-form .form-group:has(.wysiwyg-container) {
+    margin-bottom: 20px;
+}
+
+.wysiwyg-label {
+    display: block;
+    margin-bottom: 8px;
+    font-weight: 600;
+    color: #374151;
+}
+
+/* Character count */
+.wysiwyg-char-count {
+    margin-top: 8px;
+    font-size: 12px;
+    color: #6b7280;
+    text-align: right;
+}
+
+/* Responsive design */
+@media (max-width: 768px) {
+    .wysiwyg-toolbar {
+        padding: 6px;
+        gap: 2px;
+    }
+    
+    .wysiwyg-btn {
+        padding: 4px 6px;
+        font-size: 11px;
+    }
+    
+    .wysiwyg-content {
+        padding: 8px;
+        min-height: 300px;
+    }
+}

+ 10 - 10
includes/config.php

@@ -4,23 +4,23 @@
  */
 
 // Database settings
-define('DB_HOST', 'localhost');
-define('DB_NAME', 'website');
+define('DB_HOST', '10.8.10.31');
+define('DB_NAME', 'valtsu_webpub');
 define('DB_USER', 'root');
-define('DB_PASS', '');
+define('DB_PASS', 'jotainaivanmuuta');
 
 // Site settings
 define('SITE_TITLE', 'Publication System');
-define('DEFAULT_LANGUAGE', 'en');
+define('DEFAULT_LANGUAGE', 'fi');
 
 // LDAP settings
-define('LDAP_ENABLED', false);
-define('LDAP_HOST', 'localhost');
+define('LDAP_ENABLED', true);
+define('LDAP_HOST', '10.8.10.11');
 define('LDAP_PORT', 389);
-define('LDAP_BASE_DN', 'dc=example,dc=com');
-define('LDAP_BIND_DN', 'cn=admin,dc=example,dc=com');
-define('LDAP_BIND_PASS', '');
-define('LDAP_USER_FILTER', '(objectClass=person)');
+define('LDAP_BASE_DN', 'dc=valavuo,dc=net');
+define('LDAP_BIND_DN', 'uid=zimbra,cn=admins,cn=zimbra');
+define('LDAP_BIND_PASS', 'lLKmZlpf0');
+define('LDAP_USER_FILTER', '(&(|(uid={username})(cn={username})(sn={username})(givenName={username})(mail={username}))(objectclass=zimbraAccount)(zimbraAccountStatus=active))');
 
 // Security settings
 define('SESSION_LIFETIME', 3600); // 1 hour

+ 226 - 0
js/wysiwyg.js

@@ -0,0 +1,226 @@
+/**
+ * Simple WYSIWYG Editor
+ * Lightweight rich text editor for publication content
+ */
+
+class WYSIWYGEditor {
+    constructor(textareaId, options = {}) {
+        this.textarea = document.getElementById(textareaId);
+        this.options = {
+            toolbar: ['bold', 'italic', 'underline', '|', 'link', 'image', '|', 'ul', 'ol', '|', 'h1', 'h2', 'h3'],
+            ...options
+        };
+        
+        this.createEditor();
+        this.bindEvents();
+    }
+    
+    createEditor() {
+        // Create editor container
+        this.container = document.createElement('div');
+        this.container.className = 'wysiwyg-container';
+        
+        // Create toolbar
+        this.toolbar = document.createElement('div');
+        this.toolbar.className = 'wysiwyg-toolbar';
+        this.createToolbarButtons();
+        
+        // Create content area
+        this.content = document.createElement('div');
+        this.content.className = 'wysiwyg-content';
+        this.content.contentEditable = true;
+        
+        // Create character count
+        this.charCount = document.createElement('div');
+        this.charCount.className = 'wysiwyg-char-count';
+        
+        // Assemble editor
+        this.container.appendChild(this.toolbar);
+        this.container.appendChild(this.content);
+        this.container.appendChild(this.charCount);
+        
+        // Replace textarea
+        this.textarea.parentNode.insertBefore(this.container, this.textarea);
+        this.textarea.style.display = 'none';
+        
+        // Initialize content
+        this.content.innerHTML = this.textarea.value;
+        this.updateCharCount();
+    }
+    
+    createToolbarButtons() {
+        this.options.toolbar.forEach(item => {
+            if (item === '|') {
+                const separator = document.createElement('div');
+                separator.className = 'wysiwyg-separator';
+                this.toolbar.appendChild(separator);
+            } else {
+                const button = document.createElement('button');
+                button.className = 'wysiwyg-btn';
+                button.type = 'button';
+                button.innerHTML = this.getButtonLabel(item);
+                button.dataset.command = item;
+                
+                button.addEventListener('click', () => this.execCommand(item));
+                this.toolbar.appendChild(button);
+            }
+        });
+    }
+    
+    getButtonLabel(command) {
+        const labels = {
+            'bold': 'B',
+            'italic': 'I',
+            'underline': 'U',
+            'link': '🔗',
+            'image': '🖼️',
+            'ul': '• List',
+            'ol': '1. List',
+            'h1': 'H1',
+            'h2': 'H2',
+            'h3': 'H3'
+        };
+        return labels[command] || command;
+    }
+    
+    execCommand(command) {
+        switch (command) {
+            case 'bold':
+                document.execCommand('bold', false, null);
+                break;
+            case 'italic':
+                document.execCommand('italic', false, null);
+                break;
+            case 'underline':
+                document.execCommand('underline', false, null);
+                break;
+            case 'link':
+                this.insertLink();
+                break;
+            case 'image':
+                this.insertImage();
+                break;
+            case 'ul':
+                document.execCommand('insertUnorderedList', false, null);
+                break;
+            case 'ol':
+                document.execCommand('insertOrderedList', false, null);
+                break;
+            case 'h1':
+                this.formatHeading('h1');
+                break;
+            case 'h2':
+                this.formatHeading('h2');
+                break;
+            case 'h3':
+                this.formatHeading('h3');
+                break;
+        }
+        
+        this.content.focus();
+    }
+    
+    insertLink() {
+        const selection = window.getSelection();
+        const url = prompt('Enter URL:');
+        if (url) {
+            document.execCommand('createLink', false, url);
+        }
+    }
+    
+    insertImage() {
+        const url = prompt('Enter image URL:');
+        if (url) {
+            document.execCommand('insertImage', false, url);
+        }
+    }
+    
+    formatHeading(tag) {
+        const selection = window.getSelection();
+        const range = selection.getRangeAt(0);
+        const heading = document.createElement(tag);
+        heading.textContent = range.toString();
+        range.deleteContents();
+        range.insertNode(heading);
+    }
+    
+    bindEvents() {
+        // Update textarea when content changes
+        this.content.addEventListener('input', () => {
+            this.textarea.value = this.content.innerHTML;
+            this.updateCharCount();
+        });
+        
+        // Update content when textarea changes (for form submission)
+        this.textarea.addEventListener('input', () => {
+            this.content.innerHTML = this.textarea.value;
+            this.updateCharCount();
+        });
+        
+        // Handle paste events
+        this.content.addEventListener('paste', (e) => {
+            e.preventDefault();
+            const text = e.clipboardData.getData('text/html') || e.clipboardData.getData('text/plain');
+            document.execCommand('insertHTML', false, text);
+        });
+        
+        // Keyboard shortcuts
+        this.content.addEventListener('keydown', (e) => {
+            if (e.ctrlKey || e.metaKey) {
+                switch (e.key) {
+                    case 'b':
+                        e.preventDefault();
+                        this.execCommand('bold');
+                        break;
+                    case 'i':
+                        e.preventDefault();
+                        this.execCommand('italic');
+                        break;
+                    case 'u':
+                        e.preventDefault();
+                        this.execCommand('underline');
+                        break;
+                }
+            }
+        });
+    }
+    
+    updateCharCount() {
+        const text = this.content.innerText || this.content.textContent || '';
+        const count = text.length;
+        this.charCount.textContent = `Characters: ${count}`;
+    }
+    
+    getContent() {
+        return this.content.innerHTML;
+    }
+    
+    setContent(html) {
+        this.content.innerHTML = html;
+        this.textarea.value = html;
+        this.updateCharCount();
+    }
+    
+    destroy() {
+        this.textarea.style.display = 'block';
+        this.textarea.value = this.content.innerHTML;
+        this.container.remove();
+    }
+}
+
+// Initialize editor when DOM is ready
+document.addEventListener('DOMContentLoaded', () => {
+    const editor = new WYSIWYGEditor('content');
+    
+    // Make editor globally accessible
+    window.wysiwygEditor = editor;
+    
+    // Handle form submission
+    const form = document.querySelector('.publication-form');
+    if (form) {
+        form.addEventListener('submit', () => {
+            // Ensure textarea has latest content
+            document.getElementById('content').value = editor.getContent();
+        });
+    }
+});

+ 1 - 0
languages/fi.php

@@ -225,6 +225,7 @@ return [
     'admin_nav_categories' => 'Kategoriat',
     'admin_nav_ldap_users' => 'LDAP-käyttäjät',
     'admin_nav_logout' => 'Kirjaudu ulos',
+    'admin_nav_users' => 'Käyttäjät',
     'admin_welcome' => 'Tervetuloa',
     'admin_overview' => 'Yleiskatsaus',
     'admin_total_publications' => 'Julkaisut yhteensä',

+ 118 - 0
test_wysiwyg.html

@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>WYSIWYG Editor Test</title>
+    <link rel="stylesheet" href="css/wysiwyg.css">
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            max-width: 800px;
+            margin: 0 auto;
+            padding: 20px;
+        }
+        .test-form {
+            margin-top: 20px;
+        }
+        .btn {
+            padding: 10px 20px;
+            border: none;
+            border-radius: 4px;
+            cursor: pointer;
+            margin: 5px;
+        }
+        .btn-primary {
+            background-color: #3b82f6;
+            color: white;
+        }
+        .btn-secondary {
+            background-color: #6b7280;
+            color: white;
+        }
+        .output {
+            margin-top: 20px;
+            padding: 15px;
+            border: 1px solid #d1d5db;
+            border-radius: 4px;
+            background-color: #f9fafb;
+        }
+    </style>
+</head>
+<body>
+    <h1>WYSIWYG Editor Test</h1>
+    
+    <form class="test-form" id="testForm">
+        <div class="form-group">
+            <label for="title">Title:</label>
+            <input type="text" id="title" name="title" value="Test Publication">
+        </div>
+        
+        <div class="form-group">
+            <label for="content" class="wysiwyg-label">Content:</label>
+            <textarea id="content" name="content" rows="20" style="display: none;">
+                <h2>Welcome to the WYSIWYG Editor</h2>
+                <p>This is a <strong>test</strong> of the rich text editor. You can:</p>
+                <ul>
+                    <li>Format text with <strong>bold</strong>, <em>italic</em>, and <u>underline</u></li>
+                    <li>Create headings (H1, H2, H3)</li>
+                    <li>Add links and images</li>
+                    <li>Create ordered and unordered lists</li>
+                </ul>
+                <p>Try editing this content to test the editor features!</p>
+            </textarea>
+        </div>
+        
+        <div class="form-actions">
+            <button type="submit" class="btn btn-primary">Submit Form</button>
+            <button type="button" class="btn btn-secondary" onclick="showContent()">Show Content</button>
+            <button type="button" class="btn btn-secondary" onclick="clearContent()">Clear</button>
+        </div>
+    </form>
+    
+    <div id="output" class="output" style="display: none;">
+        <h3>Form Output:</h3>
+        <pre id="outputText"></pre>
+    </div>
+    
+    <div id="preview" class="output" style="display: none;">
+        <h3>Content Preview:</h3>
+        <div id="previewContent"></div>
+    </div>
+    
+    <script src="js/wysiwyg.js"></script>
+    <script>
+        // Override the default initialization since we're not in the admin context
+        document.addEventListener('DOMContentLoaded', () => {
+            const editor = new WYSIWYGEditor('content');
+            window.wysiwygEditor = editor;
+            
+            // Handle form submission
+            const form = document.getElementById('testForm');
+            form.addEventListener('submit', (e) => {
+                e.preventDefault();
+                showContent();
+            });
+        });
+        
+        function showContent() {
+            const content = document.getElementById('content').value;
+            const title = document.getElementById('title').value;
+            
+            // Show raw content
+            document.getElementById('outputText').textContent = `Title: ${title}\nContent: ${content}`;
+            document.getElementById('output').style.display = 'block';
+            
+            // Show preview
+            document.getElementById('previewContent').innerHTML = content;
+            document.getElementById('preview').style.display = 'block';
+        }
+        
+        function clearContent() {
+            window.wysiwygEditor.setContent('');
+            document.getElementById('output').style.display = 'none';
+            document.getElementById('preview').style.display = 'none';
+        }
+    </script>
+</body>
+</html>