PHP Classes

File: templates/shared_message.twig

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   templates/shared_message.twig   Download  
File: templates/shared_message.twig
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 18,594 bytes
 

Contents

Class file image Download
{% extends "base.twig" %} {% block title %}{% if message and message.subject %}{{ message.subject }} | {{ t('ui.shared_message.title', {}, locale, ['common']) }}{% else %}{{ t('ui.shared_message.title', {}, locale, ['common']) }}{% endif %} - {{ parent() }}{% endblock %} {% block meta_description_tags %} {% if message %} {% if ai_og_summary %} {% set description = ai_og_summary %} <meta name="description" content="{{ description|e }}"> <meta property="og:description" content="{{ description|e }}"> {% else %} {# Fallback: first 160 chars of body #} {% set description = message.message_text|striptags|slice(0, 160)|trim %} {% if description %} <meta name="description" content="{{ description }}{% if description|length >= 160 %}...{% endif %}"> <meta property="og:description" content="{{ description }}{% if description|length >= 160 %}...{% endif %}"> {% endif %} {% endif %} {% else %} {{ parent() }} {% endif %} {% endblock %} {% block meta_tags %} {% if message %} {% set description = ai_og_summary ? ai_og_summary : (message.message_text|striptags|slice(0, 160)|trim) %} {# Open Graph meta tags for social media sharing #} <meta property="og:title" content="{% if message.subject %}{{ message.subject }}{% else %}{{ t('ui.shared_message.title', {}, locale, ['common']) }}{% endif %}"> <meta property="og:type" content="article"> <meta property="og:url" content="{{ share_url }}"> {% if message.from_name %} <meta property="og:site_name" content="{{ system_name }}"> <meta property="article:author" content="{{ message.from_name }}"> {% endif %} {% if message.date_written %} <meta property="article:published_time" content="{{ message.date_written }}"> {% endif %} {% if og_image_url %} <meta property="og:image" content="{{ og_image_url }}"> {% if og_image_mime %}<meta property="og:image:type" content="{{ og_image_mime }}">{% endif %} {% if og_image_width %}<meta property="og:image:width" content="{{ og_image_width }}">{% endif %} {% if og_image_height %}<meta property="og:image:height" content="{{ og_image_height }}">{% endif %} <meta name="twitter:card" content="summary_large_image"> {% else %} <meta name="twitter:card" content="summary"> {% endif %} <meta name="twitter:title" content="{% if message.subject %}{{ message.subject }}{% else %}{{ t('ui.shared_message.title', {}, locale, ['common']) }}{% endif %}"> {% if description %} <meta name="twitter:description" content="{{ description }}{% if description|length >= 160 %}...{% endif %}"> {% endif %} {% if og_image_url %} <meta name="twitter:image" content="{{ og_image_url }}"> {% endif %} {# Additional meta tags #} {% if message.echoarea %} <meta name="keywords" content="FidoNet, {{ message.echoarea }}, echomail, message board, BBS"> {% else %} <meta name="keywords" content="FidoNet, netmail, BBS, message"> {% endif %} {% endif %} <link href="/css/ansisys.css" rel="stylesheet"> <script src="/js/ansisys.js"></script> {% endblock %} {% block content %} <div class="container-fluid"> <div class="row justify-content-center"> <div class="col-lg-8 col-md-10"> <!-- Shared Message Header --> <div class="alert alert-info mb-4" id="shareInfo" style="display: none;"> <div class="d-flex align-items-center"> <i class="fas fa-share-alt me-2"></i> <div> <strong>{{ t('ui.shared_message.title', {}, locale, ['common']) }}</strong> </div> </div> </div> <!-- Message Card --> <div class="card" id="messageCard" style="display: none;"> <div class="card-header"> <div class="d-flex justify-content-between align-items-center"> <h5 class="mb-0" id="messageSubject">{{ t('ui.common.loading', {}, locale, ['common']) }}</h5> <div class="btn-group btn-group-sm"> <a href="/login" class="btn btn-outline-primary" id="loginBtn" style="display: none;"> <i class="fas fa-sign-in-alt"></i> {{ t('ui.shared_message.login_to_reply', {}, locale, ['common']) }} </a> <a href="/register" class="btn btn-outline-secondary" id="registerBtn" style="display: none;"> <i class="fas fa-user-plus"></i> {{ t('ui.register.title', {}, locale, ['common']) }} </a> </div> </div> </div> <div class="card-body"> <div id="messageContent"> <div class="loading-spinner text-center py-4"> <i class="fas fa-spinner fa-spin me-2"></i> {{ t('ui.shared_message.loading', {}, locale, ['common']) }} </div> </div> </div> <div class="card-footer text-muted small"> <div class="row"> <div class="col-md-6"> <i class="fas fa-info-circle me-1"></i> {{ t('ui.shared_message.shared_on', {}, locale, ['common']) }} <span id="shareDate"></span> </div> <div class="col-md-6 text-md-end"> <span id="shareStats"></span> </div> </div> </div> </div> <!-- Error Display --> <div class="alert alert-danger" id="errorMessage" style="display: none;"> <div class="d-flex align-items-center"> <i class="fas fa-exclamation-triangle me-2"></i> <div> <strong>{{ t('ui.shared_message.unable_to_load', {}, locale, ['common']) }}</strong> <p class="mb-0 mt-1" id="errorText"></p> </div> </div> <div class="mt-3"> <a href="/" class="btn btn-primary"> <i class="fas fa-home"></i> {{ t('ui.shared_message.go_to_main_site', {}, locale, ['common']) }} </a> </div> </div> <!-- Authentication Required --> <div class="alert alert-warning" id="authRequired" style="display: none;"> <div class="d-flex align-items-center"> <i class="fas fa-lock me-2"></i> <div> <strong>{{ t('ui.shared_message.login_required', {}, locale, ['common']) }}</strong> <p class="mb-0 mt-1">{{ t('ui.shared_message.login_required_help', {}, locale, ['common']) }}</p> </div> </div> <div class="mt-3"> <a href="/login" class="btn btn-primary me-2"> <i class="fas fa-sign-in-alt"></i> {{ t('ui.base.login', {}, locale, ['common']) }} </a> <a href="/register" class="btn btn-outline-primary"> <i class="fas fa-user-plus"></i> {{ t('ui.register.title', {}, locale, ['common']) }} </a> </div> </div> <!-- About This System --> <div class="card mt-4"> <div class="card-body"> <h6 class="card-title"> <i class="fas fa-info-circle me-2"></i> {{ t('ui.shared_message.about_this_message', {}, locale, ['common']) }} </h6> <p class="card-text"> {{ t('ui.shared_message.about_text', {}, locale, ['common']) }} </p> <div class="alert alert-primary" id="registrationPrompt" style="display: none;"> <div class="d-flex align-items-start"> <i class="fas fa-user-plus me-3 mt-1"></i> <div class="flex-grow-1"> <h6 class="alert-heading mb-2">{{ t('ui.shared_message.join_conversation', {}, locale, ['common']) }}</h6> <p class="mb-2"> {{ t('ui.shared_message.join_conversation_help', {}, locale, ['common']) }} </p> <div class="d-flex gap-2 flex-wrap"> <a href="/register" class="btn btn-primary btn-sm"> <i class="fas fa-user-plus me-1"></i> {{ t('ui.shared_message.register_now', {}, locale, ['common']) }} </a> <a href="/login" class="btn btn-outline-primary btn-sm"> <i class="fas fa-sign-in-alt me-1"></i> {{ t('ui.shared_message.already_have_account', {}, locale, ['common']) }} </a> </div> </div> </div> </div> <div class="row"> <div class="col-md-6"> <small class="text-muted"> <i class="fas fa-network-wired me-1"></i> <strong>{{ t('ui.shared_message.network', {}, locale, ['common']) }}:</strong> <span id="networkName">{{ t('ui.common.loading', {}, locale, ['common']) }}</span> </small> </div> <div class="col-md-6"> <small class="text-muted"> <i class="fas fa-code me-1"></i> <strong>{{ t('ui.shared_message.powered_by', {}, locale, ['common']) }}:</strong> BinktermPHP </small> </div> </div> </div> </div> </div> </div> </div> {% endblock %} {% block scripts %} <script> const shareKey = '{{ shareKey|default('') }}'; const shareArea = '{{ shareArea|default('')|e('js') }}'; const shareSlug = '{{ shareSlug|default('')|e('js') }}'; function apiError(payload, fallback) { if (window.getApiErrorMessage) { return window.getApiErrorMessage(payload, fallback); } return payload && payload.error ? payload.error : fallback; } function uiT(key, fallback, params = {}) { if (window.t) { return window.t(key, params, fallback); } return fallback; } $(document).ready(function() { loadSharedMessage(); loadUserSettings(); }); function loadSharedMessage() { const apiUrl = shareKey ? `/api/messages/shared/${shareKey}` : `/api/messages/shared/${encodeURIComponent(shareArea)}/${encodeURIComponent(shareSlug)}`; $.get(apiUrl) .done(function(data) { if (data.success) { displaySharedMessage(data.message, data.share_info); } else { showError(apiError(data, uiT('ui.shared_message.load_failed', 'Failed to load shared message'))); } }) .fail(function(xhr) { if (xhr.status === 401) { showAuthRequired(); } else if (xhr.status === 404) { showError(uiT('ui.shared_message.not_available', 'This shared message is not available. It may have expired or been revoked.')); } else { showError(uiT('ui.shared_message.load_failed_retry', 'Failed to load the shared message. Please try again later.')); } }); } function displaySharedMessage(message, shareInfo) { // Set message subject $('#messageSubject').text(message.subject || uiT('messages.no_subject', '(No Subject)')); // Parse message to separate kludge lines from body const parsedMessage = parseEchomailMessage(message.message_text || '', message.kludge_lines || ''); const bodyHtml = message.markup_html ? message.markup_html : formatMessageBodyForDisplay(message, parsedMessage.messageBody); // Build message content const html = ` <div class="message-header-full mb-3"> <div class="row"> <div class="col-md-6"> <strong>${uiT('ui.shared_message.from_label', 'From:')}</strong> ${escapeHtml(message.from_name)}<br> <small class="text-muted">${formatFidonetAddress(message.from_address, message.from_system_name)}</small> </div> <div class="col-md-6"> <strong>${uiT('ui.shared_message.to_label', 'To:')}</strong> ${escapeHtml(message.to_name || uiT('ui.common.all', 'All'))}<br> ${message.echoarea ? `<span class="badge" style="background-color: ${message.echoarea_color || '#28a745'}; color: white;">${message.echoarea}</span>` : ''} </div> </div> <div class="row mt-2"> <div class="col-md-6"> <strong>${uiT('ui.shared_message.date_label', 'Date:')}</strong> ${formatFullDate(message.date_written)} </div> <div class="col-md-6"> <strong>${uiT('ui.shared_message.subject_label', 'Subject:')}</strong> ${escapeHtml(message.subject || uiT('messages.no_subject', '(No Subject)'))} </div> </div> </div> <div class="message-text"> ${bodyHtml} </div> ${message.origin_line ? `<div class="message-origin mt-2"><small class="text-muted">${escapeHtml(message.origin_line)}</small></div>` : ''} `; const messageContent = document.getElementById('messageContent'); if (window.BinkMediaPlayer) { BinkMediaPlayer.cleanup(messageContent); } $('#messageContent').html(html); if (window.BinkMediaPlayer) { BinkMediaPlayer.scan(messageContent); } $('#messageCard').show(); // Show share info const sharedDate = formatDate(shareInfo.created_at); const accessCount = shareInfo.access_count || 0; $('#shareDate').text(sharedDate); $('#shareStats').text(uiT('ui.shared_message.viewed_times', 'Viewed {count} times', { count: accessCount })); $('#shareInfo').show(); // Show login/register buttons for anonymous users if not a public share const isLoggedIn = checkUserStatus(); if (!isLoggedIn && !shareInfo.is_public) { $('#loginBtn, #registerBtn').show(); } // Show registration prompt for anonymous users if (!isLoggedIn) { $('#registrationPrompt').show(); } // Set network name const networkName = message.echoarea_domain || uiT('ui.shared_message.local_bulletin_board', 'Local Bulletin Board'); $('#networkName').text(networkName); } function showError(errorText) { $('#errorText').text(errorText); $('#errorMessage').show(); } function showAuthRequired() { $('#authRequired').show(); } function checkUserStatus() { // Check if user is logged in by looking for the session cookie const sessionCookie = document.cookie .split('; ') .find(row => row.startsWith('binktermphp_session=')); return !!sessionCookie; } function loadUserSettings() { // Load font settings if user is logged in if (checkUserStatus()) { $.get('/api/user/settings') .done(function(data) { const fontFamily = data.font_family || 'Courier New, Monaco, Consolas, monospace'; const fontSize = data.font_size || 16; // Apply font settings to message text const css = ` .message-text, .message-text pre, .message-formatted { font-family: ${fontFamily} !important; font-size: ${fontSize}px !important; } `; $('<style id="user-font-styles">' + css + '</style>').appendTo('head'); }) .fail(function() { console.log('Failed to load font settings, using defaults'); }); } } // Global settings for message parsing window.userSettings = { timezone: 'America/Los_Angeles' // Default timezone }; </script> <style> /* Shared message specific styles */ .message-header-full { background-color: #f8f9fa; border-radius: 0.375rem; padding: 1rem; border: 1px solid #dee2e6; } .message-text { font-family: 'Courier New', Monaco, Consolas, monospace; font-size: 16px; line-height: 1.4; white-space: pre-wrap; word-wrap: break-word; } .message-formatted { font-family: 'Courier New', Monaco, Consolas, monospace; } .message-preformatted { background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 0.375rem; padding: 1rem; font-size: 0.875rem; overflow-x: auto; } .message-quote { border-left: 3px solid #6c757d; padding-left: 1rem; margin: 0.5rem 0; color: #6c757d; } .message-signature { color: #6c757d; font-style: italic; } .message-signature-separator { color: #adb5bd; text-align: center; margin: 1rem 0; } .quote-line { margin: 0.25rem 0; } .message-paragraph { margin: 0.5rem 0; } .message-origin { border-top: 1px solid #dee2e6; padding-top: 0.5rem; margin-top: 1rem; } /* Loading spinner */ .loading-spinner { color: #6c757d; } /* Responsive adjustments */ @media (max-width: 768px) { .message-text { font-size: 14px; } .message-header-full { padding: 0.75rem; } } </style> {% endblock %}