Skip to main content

Overview

The Procedures module (Procedimientos) provides a comprehensive documentation system with a rich text editor, internal linking, search functionality, and collaboration features. It’s designed for creating and maintaining internal process documentation.

User Guide

Complete guide for creating and managing procedures

Key Features

Rich Text Editor

Quill editor with formatting, tables, and media support

Advanced Search

Search by title and content with match highlighting

Internal Linking

Cross-reference between related procedures

Real-time Sync

Changes sync instantly via Firebase

Table Support

Better-table plugin for complex data structures

Permission Control

Role-based editing and deletion permissions

Rich Text Editor

The Procedures module uses Quill as its rich text editor with the better-table extension:
<!-- Quill CSS -->
<link href="https://cdn.quilljs.com/1.3.7/quill.snow.css" rel="stylesheet">
<link href="https://unpkg.com/[email protected]/dist/quill-better-table.css" rel="stylesheet">

<!-- Quill JS -->
<script src="https://cdn.quilljs.com/1.3.7/quill.js"></script>

Editor Configuration

var quill = new Quill('#editor', {
    theme: 'snow',
    modules: {
        toolbar: [
            [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
            ['bold', 'italic', 'underline', 'strike'],
            ['blockquote', 'code-block'],
            [{ 'list': 'ordered'}, { 'list': 'bullet' }],
            [{ 'script': 'sub'}, { 'script': 'super' }],
            [{ 'indent': '-1'}, { 'indent': '+1' }],
            [{ 'direction': 'rtl' }],
            [{ 'size': ['small', false, 'large', 'huge'] }],
            [{ 'color': [] }, { 'background': [] }],
            [{ 'font': [] }],
            [{ 'align': [] }],
            ['link', 'image', 'video'],
            ['clean'],
            ['table']
        ],
        table: true,
        'better-table': {
            operationMenu: {
                items: {
                    unmergeCells: {
                        text: 'Separar celdas'
                    },
                    insertColumnRight: {
                        text: 'Insertar columna a la derecha'
                    },
                    insertColumnLeft: {
                        text: 'Insertar columna a la izquierda'
                    },
                    insertRowUp: {
                        text: 'Insertar fila arriba'
                    },
                    insertRowDown: {
                        text: 'Insertar fila abajo'
                    },
                    removeRow: {
                        text: 'Eliminar fila'
                    },
                    removeColumn: {
                        text: 'Eliminar columna'
                    },
                    removeTable: {
                        text: 'Eliminar tabla'
                    }
                }
            }
        }
    }
});

Supported Formatting

  • Bold, Italic, Underline, Strikethrough
  • Headers (H1-H6)
  • Font size and family
  • Text color and background
  • Subscript and superscript

Procedure Structure

Each procedure document has the following data structure:
{
  titulo: "Procedure Title",
  contenido: "<h1>Rich HTML Content</h1><p>...</p>",
  enlaces: {
    "Related Procedure 1": true,
    "Related Procedure 2": true
  },
  autor: "Nombre_del_Creador",
  timestamp: 1234567890,
  ultimaModificacion: 1234567900
}

Search Functionality

The search system provides comprehensive filtering:
function buscarPorTitulo(query) {
    const procedimientos = document.querySelectorAll('.procedimiento-item');
    const normalizedQuery = query.toLowerCase();
    
    procedimientos.forEach(item => {
        const titulo = item.dataset.titulo.toLowerCase();
        if (titulo.includes(normalizedQuery)) {
            item.style.display = 'block';
            highlightMatch(item, query);
        } else {
            item.style.display = 'none';
        }
    });
}
Search within procedure content for specific terms:
function buscarEnContenido(query) {
    const query_lower = query.toLowerCase();
    
    firebase.database().ref('procedimientos').once('value', snapshot => {
        const resultados = [];
        
        snapshot.forEach(child => {
            const proc = child.val();
            const contenidoTexto = stripHTML(proc.contenido).toLowerCase();
            
            if (contenidoTexto.includes(query_lower)) {
                resultados.push({
                    titulo: proc.titulo,
                    coincidencias: countMatches(contenidoTexto, query_lower)
                });
            }
        });
        
        mostrarResultadosBusqueda(resultados);
    });
}

function stripHTML(html) {
    const tmp = document.createElement('div');
    tmp.innerHTML = html;
    return tmp.textContent || tmp.innerText || '';
}

Search Highlighting

Matched terms are highlighted in search results:
function highlightMatch(element, query) {
    const texto = element.textContent;
    const regex = new RegExp(`(${query})`, 'gi');
    const highlighted = texto.replace(regex, '<mark>$1</mark>');
    element.innerHTML = highlighted;
}
Search is case-insensitive and supports partial matches for flexible discovery.

Internal Linking

Procedures can reference other related procedures:
1

Access link manager

While editing a procedure, click the Enlaces relacionados (Related Links) button.
2

Select procedures

Choose from a list of available procedures to link.
function cargarProcedimientosDisponibles() {
    firebase.database().ref('procedimientos').once('value', snapshot => {
        const select = document.getElementById('selectProcedimiento');
        
        snapshot.forEach(child => {
            const titulo = child.key;
            if (titulo !== procedimientoActual) {
                const option = document.createElement('option');
                option.value = titulo;
                option.textContent = titulo;
                select.appendChild(option);
            }
        });
    });
}
3

Save links

Links are saved to the procedure’s enlaces object in Firebase.
function agregarEnlace(procedimientoOrigen, procedimientoDestino) {
    firebase.database()
        .ref(`procedimientos/${procedimientoOrigen}/enlaces/${procedimientoDestino}`)
        .set(true);
}
Related procedures appear as clickable links below the main content:
function mostrarEnlaces(enlaces) {
    const container = document.getElementById('enlacesContainer');
    container.innerHTML = '<h3>Procedimientos relacionados:</h3>';
    
    Object.keys(enlaces || {}).forEach(enlace => {
        const link = document.createElement('a');
        link.href = '#';
        link.textContent = enlace;
        link.onclick = () => cargarProcedimiento(enlace);
        
        container.appendChild(link);
    });
}

CRUD Operations

Creating Procedures

function crearProcedimiento(titulo, contenido, autor) {
    const procedimientoData = {
        titulo: titulo,
        contenido: contenido,
        autor: autor,
        timestamp: Date.now(),
        ultimaModificacion: Date.now(),
        enlaces: {}
    };
    
    return firebase.database()
        .ref(`procedimientos/${titulo}`)
        .set(procedimientoData);
}

Reading Procedures

function cargarProcedimiento(titulo) {
    firebase.database().ref(`procedimientos/${titulo}`).once('value', snapshot => {
        const proc = snapshot.val();
        
        if (proc) {
            document.getElementById('titulo').textContent = proc.titulo;
            quill.root.innerHTML = proc.contenido;
            mostrarEnlaces(proc.enlaces);
            mostrarMetadatos(proc.autor, proc.timestamp, proc.ultimaModificacion);
        }
    });
}

Updating Procedures

function actualizarProcedimiento(titulo, nuevoContenido) {
    return firebase.database()
        .ref(`procedimientos/${titulo}`)
        .update({
            contenido: nuevoContenido,
            ultimaModificacion: Date.now()
        });
}

Deleting Procedures

function eliminarProcedimiento(titulo, usuarioActual) {
    // Check permissions
    if (!tienePermisoEliminacion(usuarioActual)) {
        alert('No tienes permisos para eliminar procedimientos');
        return;
    }
    
    if (confirm(`¿Estás seguro de eliminar "${titulo}"?`)) {
        firebase.database()
            .ref(`procedimientos/${titulo}`)
            .remove()
            .then(() => {
                alert('Procedimiento eliminado exitosamente');
                listarProcedimientos();
            })
            .catch(error => {
                console.error('Error al eliminar:', error);
            });
    }
}
Deletion is permanent and cannot be undone. Always confirm before deleting procedures.

Permission System

The module implements role-based access control:
const PERMISOS = {
    'Andrés_Felipe_Yepes_Tascón': {
        crear: true,
        editar: true,
        eliminar: true
    },
    'default': {
        crear: true,
        editar: true,
        eliminar: false
    }
};

function tienePermiso(usuario, accion) {
    const permisos = PERMISOS[usuario] || PERMISOS['default'];
    return permisos[accion] || false;
}

Permission Levels

Full access to create, edit, and delete all procedures.
Can create and edit procedures, but cannot delete them.
Read-only access to view procedures and search content.

Real-time Collaboration

Multiple users can work simultaneously with automatic updates:
// Listen for new procedures
firebase.database().ref('procedimientos').on('child_added', snapshot => {
    agregarProcedimientoLista(snapshot.key, snapshot.val());
});

// Listen for updates
firebase.database().ref('procedimientos').on('child_changed', snapshot => {
    actualizarProcedimientoLista(snapshot.key, snapshot.val());
});

// Listen for deletions
firebase.database().ref('procedimientos').on('child_removed', snapshot => {
    eliminarProcedimientoLista(snapshot.key);
});

Export Capabilities

Export procedures to various formats:

HTML Export

function exportarHTML(titulo, contenido) {
    const html = `
<!DOCTYPE html>
<html>
<head>
    <title>${titulo}</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
    </style>
</head>
<body>
    <h1>${titulo}</h1>
    ${contenido}
</body>
</html>
    `;
    
    downloadFile(`${titulo}.html`, html, 'text/html');
}

PDF Export

Use the browser’s print functionality to export as PDF:
function exportarPDF() {
    window.print();
}

Plain Text Export

function exportarTexto(titulo, contenido) {
    const texto = stripHTML(contenido);
    downloadFile(`${titulo}.txt`, texto, 'text/plain');
}

Best Practices

Descriptive Titles

Use clear, descriptive titles that indicate the procedure’s purpose

Consistent Structure

Maintain consistent formatting across all procedures

Regular Updates

Keep procedures current by reviewing and updating regularly

Cross-Reference

Link related procedures to create a knowledge network

Troubleshooting

Ensure Quill CDN scripts are loaded. Check browser console for errors. Verify internet connection.
Check Firebase connection status. Verify write permissions. Ensure authentication is active.
Confirm better-table plugin is loaded. Check that table module is enabled in Quill config.
Verify search query. Check that procedures contain searchable content. Try title-only search.

Working with Procedures

Complete user guide with examples

Firebase Integration

How Firebase powers real-time updates

User Management

Manage permissions and access control

Data Export

Export procedures to various formats

Build docs developers (and LLMs) love