Add module overrides with showtitle, fix footer and a11y positioning
New module overrides with showtitle support: - mod_stats, mod_feed, mod_wrapper, mod_whosonline, mod_users_latest Footer CSS: - Each footer module now stacks full-width (flex-direction: column) - Remove hardcoded padding-right: 300px inline style - Dynamic footer padding-right based on theme FAB and a11y toolbar Accessibility toolbar positioning: - Toolbar now sits to the right of the theme FAB (bottom-right area) - Shifts automatically when theme FAB is enabled via CSS attribute selectors on body data attributes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
88
src/html/mod_feed/default.php
Normal file
88
src/html/mod_feed/default.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
*
|
||||||
|
* This file is part of a Moko Consulting project.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default layout override for mod_feed.
|
||||||
|
* Adds showtitle support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
use Joomla\CMS\HTML\HTMLHelper;
|
||||||
|
|
||||||
|
if (!$feed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$rssurl = $params->get('rssurl', '');
|
||||||
|
$rsstitle = $params->get('rsstitle', 1);
|
||||||
|
$rssdesc = $params->get('rssrtl', 0) ? ' feed-rtl' : '';
|
||||||
|
$rssimage = $params->get('rssimage', 1);
|
||||||
|
$rssitems = $params->get('rssitems', 5);
|
||||||
|
$rssitemdesc = $params->get('rssitemdesc', 1);
|
||||||
|
$word_count = $params->get('word_count', 0);
|
||||||
|
?>
|
||||||
|
<div class="mod-feed<?php echo $suffix ? ' ' . $suffix : ''; ?><?php echo $rssdesc; ?>">
|
||||||
|
<?php if ($module->showtitle) : ?>
|
||||||
|
<<?php echo $headerTag; ?> class="mod-feed__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($feed->title && $rsstitle) : ?>
|
||||||
|
<h4 class="mod-feed__feed-title">
|
||||||
|
<?php if (!empty($rssurl)) : ?>
|
||||||
|
<a href="<?php echo htmlspecialchars($rssurl, ENT_COMPAT, 'UTF-8'); ?>" target="_blank" rel="noopener noreferrer">
|
||||||
|
<?php echo $feed->title; ?>
|
||||||
|
</a>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php echo $feed->title; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</h4>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($feed->description && $rssdesc) : ?>
|
||||||
|
<p class="mod-feed__description"><?php echo $feed->description; ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($rssimage && $feed->image) : ?>
|
||||||
|
<img src="<?php echo $feed->image->uri; ?>" alt="<?php echo $feed->image->title ?? ''; ?>" class="mod-feed__image" />
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($feed->items)) : ?>
|
||||||
|
<ul class="mod-feed__list">
|
||||||
|
<?php for ($i = 0, $max = min(count($feed->items), $rssitems); $i < $max; $i++) :
|
||||||
|
$item = $feed->items[$i];
|
||||||
|
?>
|
||||||
|
<li class="mod-feed__item">
|
||||||
|
<?php if (!empty($item->uri)) : ?>
|
||||||
|
<a href="<?php echo htmlspecialchars($item->uri, ENT_COMPAT, 'UTF-8'); ?>" target="_blank" rel="noopener noreferrer">
|
||||||
|
<?php echo $item->title; ?>
|
||||||
|
</a>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php echo $item->title; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($rssitemdesc && !empty($item->content)) :
|
||||||
|
$desc = $item->content;
|
||||||
|
if ($word_count) {
|
||||||
|
$words = explode(' ', strip_tags($desc));
|
||||||
|
if (count($words) > $word_count) {
|
||||||
|
$desc = implode(' ', array_slice($words, 0, $word_count)) . '…';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<p class="mod-feed__item-description"><?php echo $desc; ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</li>
|
||||||
|
<?php endfor; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
76
src/html/mod_feed/index.html
Normal file
76
src/html/mod_feed/index.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
|
||||||
|
This file is part of a Moko Consulting project.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Redirecting…</title>
|
||||||
|
|
||||||
|
<!-- Search engines: do not index this placeholder redirect page -->
|
||||||
|
<meta name="robots" content="noindex, nofollow, noarchive" />
|
||||||
|
|
||||||
|
<!-- Instant redirect fallback even if JavaScript is disabled -->
|
||||||
|
<meta http-equiv="refresh" content="0; url=/" />
|
||||||
|
|
||||||
|
<!-- Canonical root reference -->
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
(function redirectToRoot() {
|
||||||
|
// Configuration object with safe defaults.
|
||||||
|
var opts = {
|
||||||
|
fallbackPath: "/", // string: fallback destination if origin is unavailable
|
||||||
|
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
|
||||||
|
behavior: "replace" // enum: "replace" | "assign"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine absolute origin in all mainstream browsers.
|
||||||
|
var origin = (typeof location.origin === "string" && location.origin)
|
||||||
|
|| (location.protocol + "//" + location.host);
|
||||||
|
|
||||||
|
// Final destination: absolute root of the current site, or fallback path.
|
||||||
|
var destination = origin ? origin + "/" : opts.fallbackPath;
|
||||||
|
|
||||||
|
function go() {
|
||||||
|
if (opts.behavior === "assign") {
|
||||||
|
location.assign(destination);
|
||||||
|
} else {
|
||||||
|
location.replace(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute redirect, optionally after a short delay.
|
||||||
|
if (opts.delayMs > 0) {
|
||||||
|
setTimeout(go, opts.delayMs);
|
||||||
|
} else {
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Secondary meta-refresh for no-JS environments is already set above.
|
||||||
|
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
|
||||||
|
<style>
|
||||||
|
html, body { height:100%; }
|
||||||
|
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||||
|
.msg { opacity: .75; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</noscript>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
37
src/html/mod_stats/default.php
Normal file
37
src/html/mod_stats/default.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
*
|
||||||
|
* This file is part of a Moko Consulting project.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default layout override for mod_stats.
|
||||||
|
* Adds showtitle support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
if (empty($list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
?>
|
||||||
|
<div class="mod-stats<?php echo $suffix ? ' ' . $suffix : ''; ?>">
|
||||||
|
<?php if ($module->showtitle) : ?>
|
||||||
|
<<?php echo $headerTag; ?> class="mod-stats__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
||||||
|
<?php endif; ?>
|
||||||
|
<ul class="mod-stats__list list-group">
|
||||||
|
<?php foreach ($list as $item) : ?>
|
||||||
|
<li class="mod-stats__item list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<?php echo $item->title; ?>
|
||||||
|
<span class="badge bg-secondary rounded-pill"><?php echo $item->data; ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
76
src/html/mod_stats/index.html
Normal file
76
src/html/mod_stats/index.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
|
||||||
|
This file is part of a Moko Consulting project.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Redirecting…</title>
|
||||||
|
|
||||||
|
<!-- Search engines: do not index this placeholder redirect page -->
|
||||||
|
<meta name="robots" content="noindex, nofollow, noarchive" />
|
||||||
|
|
||||||
|
<!-- Instant redirect fallback even if JavaScript is disabled -->
|
||||||
|
<meta http-equiv="refresh" content="0; url=/" />
|
||||||
|
|
||||||
|
<!-- Canonical root reference -->
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
(function redirectToRoot() {
|
||||||
|
// Configuration object with safe defaults.
|
||||||
|
var opts = {
|
||||||
|
fallbackPath: "/", // string: fallback destination if origin is unavailable
|
||||||
|
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
|
||||||
|
behavior: "replace" // enum: "replace" | "assign"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine absolute origin in all mainstream browsers.
|
||||||
|
var origin = (typeof location.origin === "string" && location.origin)
|
||||||
|
|| (location.protocol + "//" + location.host);
|
||||||
|
|
||||||
|
// Final destination: absolute root of the current site, or fallback path.
|
||||||
|
var destination = origin ? origin + "/" : opts.fallbackPath;
|
||||||
|
|
||||||
|
function go() {
|
||||||
|
if (opts.behavior === "assign") {
|
||||||
|
location.assign(destination);
|
||||||
|
} else {
|
||||||
|
location.replace(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute redirect, optionally after a short delay.
|
||||||
|
if (opts.delayMs > 0) {
|
||||||
|
setTimeout(go, opts.delayMs);
|
||||||
|
} else {
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Secondary meta-refresh for no-JS environments is already set above.
|
||||||
|
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
|
||||||
|
<style>
|
||||||
|
html, body { height:100%; }
|
||||||
|
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||||
|
.msg { opacity: .75; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</noscript>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
41
src/html/mod_users_latest/default.php
Normal file
41
src/html/mod_users_latest/default.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
*
|
||||||
|
* This file is part of a Moko Consulting project.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default layout override for mod_users_latest.
|
||||||
|
* Adds showtitle support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
use Joomla\CMS\HTML\HTMLHelper;
|
||||||
|
|
||||||
|
if (empty($names)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
?>
|
||||||
|
<div class="mod-users-latest<?php echo $suffix ? ' ' . $suffix : ''; ?>">
|
||||||
|
<?php if ($module->showtitle) : ?>
|
||||||
|
<<?php echo $headerTag; ?> class="mod-users-latest__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
||||||
|
<?php endif; ?>
|
||||||
|
<ul class="mod-users-latest__list">
|
||||||
|
<?php foreach ($names as $name) : ?>
|
||||||
|
<li class="mod-users-latest__item">
|
||||||
|
<?php echo htmlspecialchars($name->name, ENT_COMPAT, 'UTF-8'); ?>
|
||||||
|
<time class="mod-users-latest__date" datetime="<?php echo HTMLHelper::_('date', $name->registerDate, 'c'); ?>">
|
||||||
|
<?php echo HTMLHelper::_('date', $name->registerDate, 'DATE_FORMAT_LC3'); ?>
|
||||||
|
</time>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
76
src/html/mod_users_latest/index.html
Normal file
76
src/html/mod_users_latest/index.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
|
||||||
|
This file is part of a Moko Consulting project.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Redirecting…</title>
|
||||||
|
|
||||||
|
<!-- Search engines: do not index this placeholder redirect page -->
|
||||||
|
<meta name="robots" content="noindex, nofollow, noarchive" />
|
||||||
|
|
||||||
|
<!-- Instant redirect fallback even if JavaScript is disabled -->
|
||||||
|
<meta http-equiv="refresh" content="0; url=/" />
|
||||||
|
|
||||||
|
<!-- Canonical root reference -->
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
(function redirectToRoot() {
|
||||||
|
// Configuration object with safe defaults.
|
||||||
|
var opts = {
|
||||||
|
fallbackPath: "/", // string: fallback destination if origin is unavailable
|
||||||
|
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
|
||||||
|
behavior: "replace" // enum: "replace" | "assign"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine absolute origin in all mainstream browsers.
|
||||||
|
var origin = (typeof location.origin === "string" && location.origin)
|
||||||
|
|| (location.protocol + "//" + location.host);
|
||||||
|
|
||||||
|
// Final destination: absolute root of the current site, or fallback path.
|
||||||
|
var destination = origin ? origin + "/" : opts.fallbackPath;
|
||||||
|
|
||||||
|
function go() {
|
||||||
|
if (opts.behavior === "assign") {
|
||||||
|
location.assign(destination);
|
||||||
|
} else {
|
||||||
|
location.replace(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute redirect, optionally after a short delay.
|
||||||
|
if (opts.delayMs > 0) {
|
||||||
|
setTimeout(go, opts.delayMs);
|
||||||
|
} else {
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Secondary meta-refresh for no-JS environments is already set above.
|
||||||
|
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
|
||||||
|
<style>
|
||||||
|
html, body { height:100%; }
|
||||||
|
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||||
|
.msg { opacity: .75; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</noscript>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
src/html/mod_whosonline/default.php
Normal file
43
src/html/mod_whosonline/default.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
*
|
||||||
|
* This file is part of a Moko Consulting project.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default layout override for mod_whosonline.
|
||||||
|
* Adds showtitle support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
use Joomla\CMS\Language\Text;
|
||||||
|
|
||||||
|
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$showmode = $params->get('showmode', 0);
|
||||||
|
?>
|
||||||
|
<div class="mod-whosonline<?php echo $suffix ? ' ' . $suffix : ''; ?>">
|
||||||
|
<?php if ($module->showtitle) : ?>
|
||||||
|
<<?php echo $headerTag; ?> class="mod-whosonline__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($showmode == 0 || $showmode == 2) : ?>
|
||||||
|
<p class="mod-whosonline__count">
|
||||||
|
<?php echo Text::plural('MOD_WHOSONLINE_GUESTS', $count['guest']); ?><br />
|
||||||
|
<?php echo Text::plural('MOD_WHOSONLINE_MEMBERS', $count['user']); ?>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (($showmode == 1 || $showmode == 2) && !empty($names)) : ?>
|
||||||
|
<ul class="mod-whosonline__list">
|
||||||
|
<?php foreach ($names as $name) : ?>
|
||||||
|
<li class="mod-whosonline__item"><?php echo $name->username; ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
76
src/html/mod_whosonline/index.html
Normal file
76
src/html/mod_whosonline/index.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
|
||||||
|
This file is part of a Moko Consulting project.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Redirecting…</title>
|
||||||
|
|
||||||
|
<!-- Search engines: do not index this placeholder redirect page -->
|
||||||
|
<meta name="robots" content="noindex, nofollow, noarchive" />
|
||||||
|
|
||||||
|
<!-- Instant redirect fallback even if JavaScript is disabled -->
|
||||||
|
<meta http-equiv="refresh" content="0; url=/" />
|
||||||
|
|
||||||
|
<!-- Canonical root reference -->
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
(function redirectToRoot() {
|
||||||
|
// Configuration object with safe defaults.
|
||||||
|
var opts = {
|
||||||
|
fallbackPath: "/", // string: fallback destination if origin is unavailable
|
||||||
|
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
|
||||||
|
behavior: "replace" // enum: "replace" | "assign"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine absolute origin in all mainstream browsers.
|
||||||
|
var origin = (typeof location.origin === "string" && location.origin)
|
||||||
|
|| (location.protocol + "//" + location.host);
|
||||||
|
|
||||||
|
// Final destination: absolute root of the current site, or fallback path.
|
||||||
|
var destination = origin ? origin + "/" : opts.fallbackPath;
|
||||||
|
|
||||||
|
function go() {
|
||||||
|
if (opts.behavior === "assign") {
|
||||||
|
location.assign(destination);
|
||||||
|
} else {
|
||||||
|
location.replace(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute redirect, optionally after a short delay.
|
||||||
|
if (opts.delayMs > 0) {
|
||||||
|
setTimeout(go, opts.delayMs);
|
||||||
|
} else {
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Secondary meta-refresh for no-JS environments is already set above.
|
||||||
|
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
|
||||||
|
<style>
|
||||||
|
html, body { height:100%; }
|
||||||
|
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||||
|
.msg { opacity: .75; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</noscript>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
src/html/mod_wrapper/default.php
Normal file
39
src/html/mod_wrapper/default.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
*
|
||||||
|
* This file is part of a Moko Consulting project.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default layout override for mod_wrapper.
|
||||||
|
* Adds showtitle support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$url = htmlspecialchars($params->get('url', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$width = htmlspecialchars($params->get('width', '100%'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$height = htmlspecialchars($params->get('height', '500'), ENT_COMPAT, 'UTF-8');
|
||||||
|
$scrolling = $params->get('scrolling', 'auto');
|
||||||
|
$frameborder = $params->get('frameborder', 0) ? '1' : '0';
|
||||||
|
?>
|
||||||
|
<div class="mod-wrapper<?php echo $suffix ? ' ' . $suffix : ''; ?>">
|
||||||
|
<?php if ($module->showtitle) : ?>
|
||||||
|
<<?php echo $headerTag; ?> class="mod-wrapper__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
||||||
|
<?php endif; ?>
|
||||||
|
<iframe src="<?php echo $url; ?>"
|
||||||
|
width="<?php echo $width; ?>"
|
||||||
|
height="<?php echo $height; ?>"
|
||||||
|
scrolling="<?php echo $scrolling; ?>"
|
||||||
|
frameborder="<?php echo $frameborder; ?>"
|
||||||
|
title="<?php echo htmlspecialchars($module->title, ENT_COMPAT, 'UTF-8'); ?>"
|
||||||
|
class="mod-wrapper__iframe"
|
||||||
|
loading="lazy">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
76
src/html/mod_wrapper/index.html
Normal file
76
src/html/mod_wrapper/index.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
|
||||||
|
This file is part of a Moko Consulting project.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Redirecting…</title>
|
||||||
|
|
||||||
|
<!-- Search engines: do not index this placeholder redirect page -->
|
||||||
|
<meta name="robots" content="noindex, nofollow, noarchive" />
|
||||||
|
|
||||||
|
<!-- Instant redirect fallback even if JavaScript is disabled -->
|
||||||
|
<meta http-equiv="refresh" content="0; url=/" />
|
||||||
|
|
||||||
|
<!-- Canonical root reference -->
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
(function redirectToRoot() {
|
||||||
|
// Configuration object with safe defaults.
|
||||||
|
var opts = {
|
||||||
|
fallbackPath: "/", // string: fallback destination if origin is unavailable
|
||||||
|
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
|
||||||
|
behavior: "replace" // enum: "replace" | "assign"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine absolute origin in all mainstream browsers.
|
||||||
|
var origin = (typeof location.origin === "string" && location.origin)
|
||||||
|
|| (location.protocol + "//" + location.host);
|
||||||
|
|
||||||
|
// Final destination: absolute root of the current site, or fallback path.
|
||||||
|
var destination = origin ? origin + "/" : opts.fallbackPath;
|
||||||
|
|
||||||
|
function go() {
|
||||||
|
if (opts.behavior === "assign") {
|
||||||
|
location.assign(destination);
|
||||||
|
} else {
|
||||||
|
location.replace(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute redirect, optionally after a short delay.
|
||||||
|
if (opts.delayMs > 0) {
|
||||||
|
setTimeout(go, opts.delayMs);
|
||||||
|
} else {
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Secondary meta-refresh for no-JS environments is already set above.
|
||||||
|
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
|
||||||
|
<style>
|
||||||
|
html, body { height:100%; }
|
||||||
|
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||||
|
.msg { opacity: .75; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</noscript>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -280,9 +280,6 @@ $wa->useScript('user.js'); // js/user.js
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php if ($params_theme_control_type !== 'none') : ?>
|
|
||||||
<style>.footer { padding-right: 300px; }</style>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (trim($params_custom_head_end)) : ?><?php echo $params_custom_head_end; ?><?php endif; ?>
|
<?php if (trim($params_custom_head_end)) : ?><?php echo $params_custom_head_end; ?><?php endif; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -13992,18 +13992,27 @@ meter {
|
|||||||
color: var(--body-bg, #e6ebf1);
|
color: var(--body-bg, #e6ebf1);
|
||||||
background-color: var(--nav-bg-color);
|
background-color: var(--nav-bg-color);
|
||||||
padding-left: 100px;
|
padding-left: 100px;
|
||||||
|
padding-right: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase footer right padding when floating controls are present */
|
||||||
|
body[data-theme-fab-enabled="1"] .footer {
|
||||||
|
padding-right: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme-fab-enabled="1"][data-a11y-toolbar="1"] .footer {
|
||||||
|
padding-right: 420px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer .grid-child {
|
.footer .grid-child {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-box-align: center;
|
-webkit-box-orient: vertical;
|
||||||
-ms-flex-align: center;
|
-webkit-box-direction: normal;
|
||||||
align-items: center;
|
-ms-flex-direction: column;
|
||||||
-webkit-box-pack: justify;
|
flex-direction: column;
|
||||||
-ms-flex-pack: justify;
|
width: 100%;
|
||||||
justify-content: space-between;
|
|
||||||
padding: 2.5rem 0.5em;
|
padding: 2.5rem 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17241,15 +17250,17 @@ html.a11y-pause-animations *::after {
|
|||||||
z-index: 1201;
|
z-index: 1201;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-end;
|
||||||
gap: .25rem;
|
gap: .25rem;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
bottom: 1rem;
|
||||||
|
right: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mokoA11yToolbar.a11y-pos-tl { top: 1rem; left: 1rem; }
|
/* When theme FAB is present, shift a11y toolbar to sit to its right */
|
||||||
#mokoA11yToolbar.a11y-pos-tr { top: 1rem; right: 1rem; align-items: flex-end; }
|
body[data-theme-fab-enabled="1"] #mokoA11yToolbar {
|
||||||
#mokoA11yToolbar.a11y-pos-bl { bottom: 1rem; left: 1rem; }
|
right: calc(2.5rem + 200px);
|
||||||
#mokoA11yToolbar.a11y-pos-br { bottom: 1rem; right: 1rem; align-items: flex-end; }
|
}
|
||||||
|
|
||||||
/* Toggle button */
|
/* Toggle button */
|
||||||
.a11y-toggle {
|
.a11y-toggle {
|
||||||
|
|||||||
Reference in New Issue
Block a user