Base Directory:
/home/ecedu/public_html/new/Views/layouts
View File: article-layout.php
<?php
// Initialize variables
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$typeId = isset($_GET['type']) ? (int)$_GET['type'] : 0;
$type = $typeId;
// Always instantiate the controller
require_once __DIR__ . '/../../Controllers/MainController.php';
$controller = new MainController();
// Fetch news only if $id and $type are valid
$news = null;
if ($id > 0 && $type > 0) {
$news = $controller->getNewsById($type, $id);
$controller->increaseViewCount($type, $id);
}
// Initialize default values
$src = "";
$extra = "";
$news_tag = "";
$html_news = '';
$title = "";
$description = "";
$imagePath = "";
$author = "";
$dateStr = "";
$news_link = '';
$views = 0;
$comments = 0;
$isVideo = false;
// Extract news data if available
if (!empty($news)) {
$title = getLocalizedTitle($news, $lang);
$description = getFullDescription($news, $lang, $functions);
$imagePath = getImagePath($news, $type);
$author = getAuthor($news);
$dateStr = formatNewsDate($news);
$news_link = $news['news_link'] ?? '';
$isVideo = !empty($news_link);
}
// Set the label using switch
$label = $L['news']; // Default label
switch ($typeId) {
case 1:
$label = $L['news'];
break;
case 2:
$label = $L['conferences'];
break;
case 3:
$label = $L['activities'];
break;
case 4:
$label = $L['publications'];
break;
case 5:
$label = $L['research_articles'];
break;
case 6:
$label = $L['events_participations'];
break;
case 7:
$label = $L['education_list'];
break;
default:
$label = readMenu($menu, $typeId, $lang);
break;
}
// Get list of news by type
$list_news = ($type > 0) ? $controller->getNewsByType($type) : [];
?>
<main id="content">
<div class="container">
<div class="row">
<!--breadcrumb-->
<div class="col-12">
<div class="breadcrumb u-breadcrumb pt-3 px-0 mb-0 bg-transparent small">
<a class="breadcrumb-item" href="index.php?lang=<?= $lang ?>"><?= $L['home'] ?></a>
»
<a href="list-news.php?i=<?= $type ?>&lang=<?= $lang ?>" rel="category tag"><?php echo $label; ?></a>
»
<span class="d-none d-md-inline"><?php echo $title; ?></span>
</div>
</div>
<!--Main content-->
<div class="col-md-8">
<article class="post-1266 post type-post status-publish format-standard has-post-thumbnail hentry category-19 category-22 tag-47 tag-36" id="post-1266">
<header class="entry-header post-title">
<h1 class="entry-title display-4 display-2-lg mt-2"><?php echo $title; ?></h1>
<div class="entry-meta post-atribute mb-3 small fw-normal text-muted">
<span class="posted-on me-2 me-md-3">
<span title="<?php echo $_create_date; ?>">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-pencil-square me-1" viewBox="0 0 16 16">
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456l-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z" />
<path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a.5.5 0 0 0 1 0v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z" />
</svg>
</span>
<time class="updated d-none d-md-inline-block" datetime="<?php echo $dateStr; ?>">
( <?php echo $dateStr; ?> )
</time>
</span>
<span class="me-2 me-md-3 text-muted d-none d-md-inline-block">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-chat-left-dots me-1" viewBox="0 0 16 16">
<path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H4.414A2 2 0 0 0 3 11.586l-2 2V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12.793a.5.5 0 0 0 .854.353l2.853-2.853A1 1 0 0 1 4.414 12H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
<path d="M5 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
<?php echo $comments; ?>
<span id="num-comments">0</span>
</span><!-- comments (Desktop) -->
<span class="me-2 me-md-3 text-muted d-md-none">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-chat-left-dots me-1" viewBox="0 0 16 16">
<path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H4.414A2 2 0 0 0 3 11.586l-2 2V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12.793a.5.5 0 0 0 .854.353l2.853-2.853A1 1 0 0 1 4.414 12H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
<path d="M5 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
0
</span><!-- comments (Mobile) -->
<span class="me-2 me-md-3">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye me-1" viewBox="0 0 16 16">
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8z"/>
<path d="M1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5z"/>
</svg>
<?php echo $views; ?>
<span id="num-views">0</span>
</span><!--end view-->
</div><!-- .entry-meta -->
</header><!-- .entry-header -->
<!-- ========== محتوى الخبر ========== -->
<article class="card card-full hover-a mb-4">
<?php
if ($isVideo) {
// إذا نوع المحتوى فيديو
[$src, $extra] = makeEmbedSrc($news_link);
} else {
// إذا محتوى عادي (صورة + وصف)
?>
<figure class="image-single-wrapper">
<img width="750" height="500"
src="<?php echo $imagePath; ?>"
class="img-fluid lazy wp-post-image"
alt="<?php echo $title; ?>"
data-src="<?php echo $imagePath; ?>"
srcset="<?php echo $imagePath; ?> 1024w,
<?php echo $imagePath; ?> 300w,
<?php echo $imagePath; ?> 750w,
<?php echo $imagePath; ?> 1140w"
sizes="(max-width: 750px) 100vw, 750px" />
<figcaption class="bg-themes"></figcaption>
</figure>
<div class="card-body">
<p class="card-text"><?= htmlspecialchars($description) ?></p>
</div>
<?php
}
// 3) إذا كان لدينا رابط فيديو (src)، نعرض الـ iframe
if (!empty($src)): ?>
<figure class="wp-embed-aspect-16-9" style="width: 100%; margin: 0 auto;">
<div class="wp-block-embed__wrapper" style="width: 100%; margin: 0 auto;">
<iframe class="video-embed"
title="<?= htmlspecialchars($news_title) ?>"
src="<?= htmlspecialchars($src) ?>"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
style="width: 100%; aspect-ratio: 16 / 9; border: none;"></iframe>
</div>
<?= $extra ?>
</figure>
<?php endif; ?>
<!-- إذا كان خبر فيديو، نعرض الوصف تحته -->
<?php if ($isVideo): ?>
<div class="card-body">
<p class="card-text"><?= htmlspecialchars($description) ?></p>
</div>
<?php endif; ?>
</article><!-- .entry-content -->
<div class="mb-2"></div>
<div class="block-title-6">
<h4 class="h5 border-primary">
<span class="bg-primary text-white"><?= $label; ?></span>
</h4>
</div>
<div class="nav-slider-hover nav-dots-top-right light-dots"
data-flickity='{
"cellAlign": "right",
"rightToLeft": true,
"wrapAround": true,
"adaptiveHeight": true,
"prevNextButtons": true,
"pageDots": true,
"imagesLoaded": true
}'>
<?php if (!empty($list_news)): ?>
<?php foreach ($list_news as $news): ?>
<?php
$title = getLocalizedTitle($news, $lang);
$description = getShortDescription($news, $lang, $functions, 500);
$imagePath = getImagePath($news,$typeId);
$author = getAuthor($news);
$dateStr = formatNewsDate($news);
?>
<article class="col-12 col-md-6 col-lg-4 mb-3 m-1">
<div class="card card-full hover-a">
<!-- الصورة المصغرة -->
<div class="position-relative rounded overflow-hidden" style="aspect-ratio: 1/1;">
<a href="article.php?id=<?= $news['news_id'] ?>&type=<?= $type ?>&lang=<?= $lang ?>">
<img
class="img-fluid w-100 h-100 object-fit-cover lazy"
src="<?= htmlspecialchars($imagePath) ?>"
loading="lazy"
data-src="<?= htmlspecialchars($imagePath) ?>"
alt="<?= htmlspecialchars($title) ?>"
srcset="
<?= htmlspecialchars($imagePath) ?> 150w,
<?= htmlspecialchars($imagePath) ?> 337w,
<?= htmlspecialchars($imagePath) ?> 376w
"
sizes="(max-width: 767px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</a>
<?= playIcon($news,$lang,$type) ?>
<!-- العنوان والتاريخ فوق الصورة -->
<div class="position-absolute bottom-0 start-0 end-0 p-3 bg-shadow text-white">
<a href="article.php?id=<?= $news['news_id'] ?>&type=<?= $type ?>&lang=<?= $lang ?>">
<h5 class="card-title h5 mb-1 text-white"><?= htmlspecialchars($title) ?></h5>
</a>
<div class="card-text small text-white"><?= $dateStr ?></div>
</div>
</div>
</div>
</article>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div class="mb-3"></div>
<!--Comments-->
<div id="comments" class="mb-5">
<div id="respond" class="comment-respond">
<h3 id="reply-title" class="comment-reply-title"><?= $L['leave_comment']; ?>
<small>
<a rel="nofollow" id="cancel-comment-reply-link" href="#" onclick="event.preventDefault();" style="display:none;"></a>
</small>
</h3>
<form id="frm-comment" class="comment-form" novalidate>
<p class="comment-notes"><?=$L['fields_comment']; ?> <span class="required">*</span></p>
<div class="form-group comment-form-author">
<input class="form-control mb-4" aria-label="name" id="author"
placeholder="<?=$L['name']; ?>*" name="author" type="text"
value="" size="30" aria-required="true" required>
</div>
<div class="form-group comment-form-comment">
<textarea aria-label="comments" class="form-control mb-4"
name="comment" id="comment"
placeholder="<?=$L['comment']; ?> *" cols="45" rows="6"
required></textarea>
</div>
<p class="form-submit">
<button type="button" class="btn btn-primary btn-sm" onclick="sendComment('frm-comment');">
<?=$L['send_comment']; ?>
</button>
<br/>
<div id="comment-message"><?=$L['done_comment']; ?>.</div>
<input type="hidden" id="news_id" name="news_id" value="<?= $id; ?>" />
<input type="hidden" name="comment_id" id="comment_id" value="0" />
</p>
</form>
</div><!-- #respond -->
<p class="form-submit"><?=$L['list_comment']; ?></p>
<div id="output" class="mb-5"></div>
</div>
</article>
</div><!-- /col-md-8 -->
<?php include('right_sidebar.php'); ?>
</div>
</div>
</main>
<script>
const lang = <?= json_encode($lang) ?>;
const isListComment=true;
function postReply(commentId) {
$('#comment_id').val(commentId);
$("#author").focus();
}
function listComment() {
const fd = { news_id: <?= intval($id) ?> };
$.ajax({
url: "service/commentRead.php",
method: "POST",
data: fd,
dataType: "json",
success(data) {
console.log("comments →", data); // اطبعها مصفوفة
renderComments(data);
},
error(xhr, status, errorThrown) {
console.error("AJAX error:", status, errorThrown);
console.error("response:", xhr.responseText);
$("#news-err").text("حدث خطأ عند جلب التعليقات").fadeIn();
}
});
}
function sendComment(formId) {
$("#comment-message").hide();
const formEl = document.getElementById(formId);
const fd = new FormData(formEl);
$.ajax({
url: 'service/commentAdd.php',
type: 'POST',
data: fd,
dataType: 'json',
processData: false,
contentType: false,
success: function(data) {
if (data.error) {
alert('حدث خطأ: ' + data.error);
return;
}
listComment();
formEl.reset();
},
error: function(xhr) {
console.error('status:', xhr.status, 'body:', xhr.responseText);
alert('تعذّر إضافة التعليق، .');
}
});
return false;
}
function listReplies(commentId, data, list) {
for (var i = 0; i < data.length; i++) {
if (commentId == data[i].parent_comment_id) {
var comments = "<div class='comment-row'>"+
" <div class='comment-info'><span class='comment-row-label'><?= $L['from']; ?> :</span> <span class='posted-by'>" +
data[i]['comment_sender_name'] + " </span> <span class='comment-row-label'> <?= $L['in']; ?> </span> <span class='posted-at'>(" + fdate(data[i]['comment_at']) + ")</span></div>" +
"<div class='comment-text'>" + data[i]['comment'] + "</div>"+
"<div><a class='btn-reply' onClick='postReply(" + data[i]['comment_id'] + ")'><?= $L['send_reply']; ?></a></div>"+
"</div>";
var item = $("<li>").html(comments);
var reply_list = $('<ul>');
list.append(item);
item.append(reply_list);
listReplies(data[i].comment_id, data, reply_list);
}
}
}
function fdate(sdate) {
return localDate(sdate,lang);
}
/**
* أحصل على تاريخ محلي: ar (العراق)، ku (الكردية)، en (الإنكليزية)
* @param {string|Date} input تاريخ أو نصّ يقبله new Date()
* @param {'ar'|'ku'|'en'} lang
* @returns {string}
*
* أمثلة:
* localDate('2025-05-31', 'ar') // السبت، 31 أيار، 2025
* localDate(new Date(), 'ku') // یەکشهممه، 5 نیسان، 2025
* localDate(Date.now(), 'en') // Saturday, 5 April, 2025
*/
function localDate(input, lang = "ar") {
const date = input instanceof Date ? input : new Date(input);
/* ــ 1) جرّب Intl.DateTimeFormat عندما تتوفر المحلّيات */
const localeMap = { ar: "ar-IQ", ku: "ku-IQ", en: "en-US" };
const locale = localeMap[lang] || "ar-IQ";
try {
// في بعض المتصفحات القديمة قد ترمي Intl خطأ عند Locale غير مدعوم
const fmt = new Intl.DateTimeFormat(locale + "-u-ca-gregory", {
weekday: "long",
day: "numeric",
month: "long",
year: "numeric"
});
const formatted = fmt.format(date);
// Safari يضيف LTR mark أحيانًا، فلنُزلها
return formatted.replace(/\u200E/g, "");
} catch {
/* Fallthrough للفهرس اليدوي */
}
/* ــ 2) جداول يدوية لأيام الأسبوع وأشهر السنة إذا فشل Intl */
const days = {
ar: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"],
ku: ["یهكشهممه","دووشهممه","سێشهممه","چوارشهممه","پێنجشهممه","ههینی","شهممه"],
en: ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
};
const months = {
ar: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران",
"تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],
ku: ["کانونی یەکەم","شوبات","ئازار","نیسان","ئایار","حوزەیران",
"تەمموز","ئاب","ئەیلوول","تشرینی یەکەم","تشرینی دووەم","کانونی دووەم"],
en: ["January","February","March","April","May","June",
"July","August","September","October","November","December"]
};
const w = date.getDay(); // 0–6
const d = date.getDate(); // 1–31
const m = date.getMonth(); // 0–11
const yr = date.getFullYear();
const dayName = (days[lang] || days.ar)[w];
const monthName = (months[lang] || months.ar)[m];
// النمط: «اليوم، 5 نيسان، 2025»
return `${dayName}، ${d} ${monthName}، ${yr}`;
}
function buildCommentHtml(c, level = 0) {
const name = c.comment_sender_name || '?';
const initial = name.trim()[0].toUpperCase();
const color = nameToMetroColor(name); // لون ثابت لهذا الاسم
const isReply = level > 0;
return `
<article class="comment-box ${isReply ? 'reply-section' : ''}">
<header class="d-flex align-items-center mb-1">
<div class="user-avatar me-2" style="--av-color:${color}">${initial}</div>
<strong class="me-auto">${c.comment_sender_name}</strong>
<time class="comment-time" datetime="${c.comment_at}">
${fdate(c.comment_at)}
</time>
</header>
<div class="comment-body mb-2">
${c.comment}
</div>
<div class="comment-actions">
<a onclick="postReply(${c.comment_id})"><?= $L['send_reply']; ?></a>
</div>
</article>
`.trim();
}
const METRO_COLORS = [
'#a4c400', // Lime
'#60a917', // Green
'#008a00', // Emerald
'#00aba9', // Teal
'#1ba1e2', // Cyan
'#0050ef', // Cobalt
'#6a00ff', // Indigo
'#aa00ff', // Violet
'#f472d0', // Pink
'#d80073', // Magenta
'#a20025', // Crimson
'#e51400', // Red
'#fa6800', // Orange
'#f0a30a', // Amber
'#e3c800', // Yellow
'#825a2c', // Brown
'#6d8764', // Olive
'#647687', // Steel
'#76608a', // Mauve
'#87794e' // Taupe
];
function nameToMetroColor(name) {
// حوّل الاسم إلى قيمة hash رقمية
let hash = 0;
for (let i = 0; i < name.length; i++) {
hash = name.charCodeAt(i) + ((hash << 5) - hash);
}
// اختر لونًا من المصفوفة بناءً على hash
const index = Math.abs(hash) % METRO_COLORS.length;
return METRO_COLORS[index]; // يرجع كقيمة Hex جاهزة
}
function nameToColor(name){
let hash = 0;
for(let i=0;i<name.length;i++){
hash = name.charCodeAt(i) + ((hash << 5) - hash);
}
// حوّل الـ hash إلى لون HSL لطيف
const hue = Math.abs(hash) % 360; // 0-359
return `hsl(${hue}, 70%, 50%)`; // تشبّع وسط، إضاءة وسط
}
function buildTree(parentId, comments, level = 0){
const ul = $("<ul>");
comments.filter(c => c.parent_comment_id === parentId)
.forEach(c => {
const li = $("<li>").html(buildCommentHtml(c, level));
li.addClass("list-unstyled"); // إزالة نقط القائمة
li.append(buildTree(c.comment_id, comments, level + 1));
ul.append(li);
});
return ul;
}
// تحويل جميع الحقول الرقمية
function normalize(comments) {
return comments.map(c => ({
comment_id: Number(c.comment_id),
parent_comment_id: c.parent_comment_id != null ? Number(c.parent_comment_id) : null,
comment: c.comment,
comment_sender_name: c.comment_sender_name,
comment_sender_email: c.comment_sender_email,
comment_at: c.comment_at,
news_id: Number(c.news_id)
}));
}
// يصوّر التعليقات في الـ DOM
function renderComments(rawData) {
const comments = normalize(rawData);
$("#num-comments").text(comments.length);
const tree = buildTree(null, comments);
$("#output").empty().append(tree);
}
</script>