Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b0d1e42bab | |||
| c3a4a1f28d | |||
| 4d67a32cb0 | |||
| 6f9aa71573 | |||
| 4a18f46c68 | |||
| f5fdf6742f | |||
| fe3abf6ddb | |||
| 601cf77170 |
@@ -10,7 +10,7 @@
|
||||
<display-name>Package - MokoJoomHero</display-name>
|
||||
<org>MokoConsulting</org>
|
||||
<description>A Joomla Module designed to provide a random image from a folder with content on top as a Hero.</description>
|
||||
<version>01.06.00</version>
|
||||
<version>01.08.00</version>
|
||||
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
||||
</identity>
|
||||
<governance>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# INGROUP: moko-platform.Automation
|
||||
# VERSION: 01.04.01
|
||||
# VERSION: 01.08.00
|
||||
# BRIEF: Auto-create feature branch when an issue is opened
|
||||
|
||||
name: "Universal: Issue Branch"
|
||||
|
||||
+4
-1
@@ -1,11 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
Version format: `XX.YY.ZZ` (zero-padded semver).
|
||||
|
||||
## [Unreleased]
|
||||
## [01.08.00] --- 2026-06-04
|
||||
|
||||
## [01.04.00] - 2026-05-30
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@ This is a Joomla **package** extension (`pkg_mokojoomhero`) containing two sub-e
|
||||
|
||||
### mod_mokojoomhero (Site Module)
|
||||
- Random hero image slideshow or background video with content overlay
|
||||
- Supports image folders, YouTube, Vimeo, and local video
|
||||
- Configurable overlay, text alignment, card animation
|
||||
- **Requires** `plg_system_mokojoomhero` to be enabled — module silently skips rendering if the system plugin is disabled
|
||||
- Supports image folders, YouTube, Vimeo, local video, solid colour, gradient
|
||||
- Configurable overlay, text alignment, card animation, parallax, content animations
|
||||
- Works independently — no plugin dependency required
|
||||
|
||||
### plg_system_mokojoomhero (System Plugin)
|
||||
- License key validation — warns admin once per session if no download key configured
|
||||
- Placeholder for future system-level features
|
||||
- Auto-enabled on package install via `pkg_script.php`
|
||||
- Namespace: `Joomla\Plugin\System\MokoJoomHero`
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
DEFGROUP:
|
||||
INGROUP: Project.Documentation
|
||||
REPO:
|
||||
VERSION: 01.04.01
|
||||
VERSION: 01.08.00
|
||||
PATH: ./CODE_OF_CONDUCT.md
|
||||
BRIEF: Reference + packaging repo for Moko Consulting Developer GPT Other Default
|
||||
-->
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# FILE INFORMATION
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
FILE: ./README.md
|
||||
VERSION: 01.04.01
|
||||
VERSION: 01.08.00
|
||||
BRIEF: MokoJoomHero - Joomla Module
|
||||
-->
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFGROUP: [PROJECT_NAME]
|
||||
INGROUP: [PROJECT_NAME].Documentation
|
||||
REPO: [REPOSITORY_URL]
|
||||
PATH: /SECURITY.md
|
||||
VERSION: 01.04.01
|
||||
VERSION: 01.08.00
|
||||
BRIEF: Security vulnerability reporting and handling policy
|
||||
-->
|
||||
|
||||
|
||||
@@ -6,15 +6,24 @@
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-GB/mod_mokojoomhero.ini
|
||||
; VERSION: 01.04.01
|
||||
; VERSION: 01.08.00
|
||||
; BRIEF: Language strings for MokoJoomHero module (frontend + admin form fields)
|
||||
|
||||
MOD_MOKOJOOMHERO_NO_CONTENT="Add content to this module to display it over the hero image."
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_LABEL="Content Source"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_DESC="Choose whether to enter content manually or pull from a Joomla article."
|
||||
MOD_MOKOJOOMHERO_SOURCE_MANUAL="Manual Editor"
|
||||
MOD_MOKOJOOMHERO_SOURCE_ARTICLE="Joomla Article"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_LABEL="Article"
|
||||
MOD_MOKOJOOMHERO_ARTICLE_DESC="Select a published article to use as the hero content. The article introtext (or fulltext) is displayed."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_SELECT="- Select Article -"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_LABEL="Use Article Title"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_DESC="Replace the module title with the selected article's title."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
@@ -27,6 +36,14 @@ MOD_MOKOJOOMHERO_MODE_LOCALVIDEO="Local Video"
|
||||
MOD_MOKOJOOMHERO_MODE_COLOR="Solid Colour"
|
||||
MOD_MOKOJOOMHERO_MODE_GRADIENT="Gradient"
|
||||
|
||||
; Transition type
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_LABEL="Transition Type"
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_DESC="How images transition between slides."
|
||||
MOD_MOKOJOOMHERO_FADE_CROSSFADE="Crossfade"
|
||||
MOD_MOKOJOOMHERO_FADE_SLIDE="Slide"
|
||||
MOD_MOKOJOOMHERO_FADE_BLACK="Fade to Black"
|
||||
MOD_MOKOJOOMHERO_FADE_ZOOM="Zoom (Ken Burns)"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC="Path to folder containing hero images, relative to Joomla root (e.g. images/heroes)."
|
||||
@@ -35,6 +52,15 @@ MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slid
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Per-slide content
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_LABEL="Slide Content"
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_DESC="Define individual slides with unique images and content. When populated, this overrides the random image folder. Leave empty to use the folder-based slideshow."
|
||||
MOD_MOKOJOOMHERO_SLIDE_IMAGE_LABEL="Image"
|
||||
MOD_MOKOJOOMHERO_SLIDE_HEADING_LABEL="Heading"
|
||||
MOD_MOKOJOOMHERO_SLIDE_BODY_LABEL="Body Text"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_LABEL="Link URL"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_TEXT_LABEL="Link Text"
|
||||
|
||||
; Video settings (embedded)
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_LABEL="Video URL"
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects the source."
|
||||
@@ -43,10 +69,35 @@ MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects
|
||||
MOD_MOKOJOOMHERO_LOCAL_VIDEO_LABEL="Video File"
|
||||
MOD_MOKOJOOMHERO_LOCAL_VIDEO_DESC="Select a video file from the Media Manager (mp4, webm, ogg)."
|
||||
|
||||
; Content animation
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_LABEL="Content Animation"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DESC="Entrance animation for the overlay content when the hero scrolls into view."
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_LABEL="Animation Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_DESC="Delay before the content animation starts."
|
||||
MOD_MOKOJOOMHERO_ANIM_NONE="None"
|
||||
MOD_MOKOJOOMHERO_ANIM_FADE_IN="Fade In"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_UP="Slide Up"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_LEFT="Slide from Right"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_RIGHT="Slide from Left"
|
||||
|
||||
; Card delay
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_LABEL="Card Fade-in Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_DESC="Delay in milliseconds before the content card fades in. Set to 0 for no delay."
|
||||
|
||||
; Parallax
|
||||
MOD_MOKOJOOMHERO_PARALLAX_LABEL="Parallax Effect"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_DESC="Background moves at a slower rate than page content on scroll, creating a depth effect."
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_LABEL="Parallax Speed"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_DESC="How much the background moves relative to scroll (0.1 = subtle, 0.9 = dramatic)."
|
||||
|
||||
; Video poster
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_LABEL="Video Poster Image"
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_DESC="Fallback image displayed while the video loads. Prevents a blank hero on slow connections."
|
||||
|
||||
; Scroll indicator
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_LABEL="Show Scroll Indicator"
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_DESC="Show an animated down-arrow at the bottom of the hero prompting users to scroll."
|
||||
|
||||
; Mute toggle
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL="Show Mute Toggle"
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC="Show a mute/unmute button on the hero video. Videos always start muted (required for autoplay)."
|
||||
@@ -68,18 +119,35 @@ MOD_MOKOJOOMHERO_HERO_HEIGHT_LABEL="Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_DESC="Height of the hero section. Use px for fixed pixels (e.g. 400px) or vh for viewport height (e.g. 60vh for 60%% of screen)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Hero height (mobile)
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_LABEL="Mobile Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_DESC="Height of the hero on mobile devices. Leave empty for auto height. Uses the same units as Hero Height."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_HINT="e.g. 40vh or 300px (empty = auto)"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_LABEL="Overlay Type"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_DESC="How the overlay is applied. Solid fills evenly; gradient fades from transparent to opaque in the chosen direction."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_SOLID="Solid"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_BOTTOM="Gradient (dark at bottom)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_TOP="Gradient (dark at top)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_LEFT="Gradient (dark at left)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_RIGHT="Gradient (dark at right)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Colour"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background colour of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_VALIGN_LABEL="Vertical Alignment"
|
||||
MOD_MOKOJOOMHERO_VALIGN_DESC="Vertical position of the content within the hero."
|
||||
MOD_MOKOJOOMHERO_VALIGN_TOP="Top"
|
||||
MOD_MOKOJOOMHERO_VALIGN_CENTER="Centre"
|
||||
MOD_MOKOJOOMHERO_VALIGN_BOTTOM="Bottom"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Colour"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Colour of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
; Horizontal alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Centre"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-GB/mod_mokojoomhero.sys.ini
|
||||
; VERSION: 01.04.01
|
||||
; VERSION: 01.08.00
|
||||
; BRIEF: System language strings — used in admin Extension Manager and Module Manager
|
||||
|
||||
MOD_MOKOJOOMHERO="Module - MokoJoomHero"
|
||||
@@ -14,17 +14,36 @@ MOD_MOKOJOOMHERO_DESCRIPTION="Displays a random hero image slideshow or backgrou
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_LABEL="Content Source"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_DESC="Choose whether to enter content manually or pull from a Joomla article."
|
||||
MOD_MOKOJOOMHERO_SOURCE_MANUAL="Manual Editor"
|
||||
MOD_MOKOJOOMHERO_SOURCE_ARTICLE="Joomla Article"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_LABEL="Article"
|
||||
MOD_MOKOJOOMHERO_ARTICLE_DESC="Select a published article to use as the hero content."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_SELECT="- Select Article -"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_LABEL="Use Article Title"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_DESC="Replace the module title with the selected article's title."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
; Hero mode
|
||||
MOD_MOKOJOOMHERO_MODE_LABEL="Hero Mode"
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images, an embedded video (YouTube/Vimeo), or a local video file."
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images, an embedded video (YouTube/Vimeo), a local video file, a solid colour, or a gradient."
|
||||
MOD_MOKOJOOMHERO_MODE_IMAGES="Images"
|
||||
MOD_MOKOJOOMHERO_MODE_VIDEO="Video (YouTube/Vimeo)"
|
||||
MOD_MOKOJOOMHERO_MODE_LOCALVIDEO="Local Video"
|
||||
MOD_MOKOJOOMHERO_MODE_COLOR="Solid Colour"
|
||||
MOD_MOKOJOOMHERO_MODE_GRADIENT="Gradient"
|
||||
|
||||
; Transition type
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_LABEL="Transition Type"
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_DESC="How images transition between slides."
|
||||
MOD_MOKOJOOMHERO_FADE_CROSSFADE="Crossfade"
|
||||
MOD_MOKOJOOMHERO_FADE_SLIDE="Slide"
|
||||
MOD_MOKOJOOMHERO_FADE_BLACK="Fade to Black"
|
||||
MOD_MOKOJOOMHERO_FADE_ZOOM="Zoom (Ken Burns)"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
@@ -34,6 +53,15 @@ MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slid
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Per-slide content
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_LABEL="Slide Content"
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_DESC="Define individual slides with unique images and content."
|
||||
MOD_MOKOJOOMHERO_SLIDE_IMAGE_LABEL="Image"
|
||||
MOD_MOKOJOOMHERO_SLIDE_HEADING_LABEL="Heading"
|
||||
MOD_MOKOJOOMHERO_SLIDE_BODY_LABEL="Body Text"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_LABEL="Link URL"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_TEXT_LABEL="Link Text"
|
||||
|
||||
; Video settings (embedded)
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_LABEL="Video URL"
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects the source."
|
||||
@@ -42,31 +70,85 @@ MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects
|
||||
MOD_MOKOJOOMHERO_LOCAL_VIDEO_LABEL="Video File"
|
||||
MOD_MOKOJOOMHERO_LOCAL_VIDEO_DESC="Select a video file from the Media Manager (mp4, webm, ogg)."
|
||||
|
||||
; Content animation
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_LABEL="Content Animation"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DESC="Entrance animation for the overlay content when the hero scrolls into view."
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_LABEL="Animation Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_DESC="Delay before the content animation starts."
|
||||
MOD_MOKOJOOMHERO_ANIM_NONE="None"
|
||||
MOD_MOKOJOOMHERO_ANIM_FADE_IN="Fade In"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_UP="Slide Up"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_LEFT="Slide from Right"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_RIGHT="Slide from Left"
|
||||
|
||||
; Card delay
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_LABEL="Card Fade-in Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_DESC="Delay in milliseconds before the content card fades in. Set to 0 for no delay."
|
||||
|
||||
; Parallax
|
||||
MOD_MOKOJOOMHERO_PARALLAX_LABEL="Parallax Effect"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_DESC="Background moves at a slower rate than page content on scroll."
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_LABEL="Parallax Speed"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_DESC="How much the background moves relative to scroll (0.1 = subtle, 0.9 = dramatic)."
|
||||
|
||||
; Video poster
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_LABEL="Video Poster Image"
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_DESC="Fallback image displayed while the video loads."
|
||||
|
||||
; Scroll indicator
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_LABEL="Show Scroll Indicator"
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_DESC="Show an animated down-arrow at the bottom of the hero prompting users to scroll."
|
||||
|
||||
; Mute toggle
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL="Show Mute Toggle"
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC="Show a mute/unmute button on the hero video. Videos always start muted (required for autoplay)."
|
||||
|
||||
; Solid colour background
|
||||
MOD_MOKOJOOMHERO_BG_COLOR_LABEL="Background Colour"
|
||||
MOD_MOKOJOOMHERO_BG_COLOR_DESC="Solid background colour for the hero section."
|
||||
|
||||
; Gradient background
|
||||
MOD_MOKOJOOMHERO_GRADIENT_START_LABEL="Gradient Start Colour"
|
||||
MOD_MOKOJOOMHERO_GRADIENT_START_DESC="Starting colour of the gradient."
|
||||
MOD_MOKOJOOMHERO_GRADIENT_END_LABEL="Gradient End Colour"
|
||||
MOD_MOKOJOOMHERO_GRADIENT_END_DESC="Ending colour of the gradient."
|
||||
MOD_MOKOJOOMHERO_GRADIENT_ANGLE_LABEL="Gradient Angle"
|
||||
MOD_MOKOJOOMHERO_GRADIENT_ANGLE_DESC="Direction of the gradient in degrees (0 = bottom to top, 90 = left to right, 135 = diagonal)."
|
||||
|
||||
; Hero height
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_LABEL="Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_DESC="Height of the hero section. Use px for fixed pixels (e.g. 400px) or vh for viewport height (e.g. 60vh for 60%% of screen)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Hero height (mobile)
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_LABEL="Mobile Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_DESC="Height of the hero on mobile devices. Leave empty for auto height."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_HINT="e.g. 40vh or 300px (empty = auto)"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_LABEL="Overlay Type"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_DESC="How the overlay is applied. Solid fills evenly; gradient fades from transparent to opaque in the chosen direction."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_SOLID="Solid"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_BOTTOM="Gradient (dark at bottom)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_TOP="Gradient (dark at top)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_LEFT="Gradient (dark at left)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_RIGHT="Gradient (dark at right)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Colour"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background colour of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_VALIGN_LABEL="Vertical Alignment"
|
||||
MOD_MOKOJOOMHERO_VALIGN_DESC="Vertical position of the content within the hero."
|
||||
MOD_MOKOJOOMHERO_VALIGN_TOP="Top"
|
||||
MOD_MOKOJOOMHERO_VALIGN_CENTER="Centre"
|
||||
MOD_MOKOJOOMHERO_VALIGN_BOTTOM="Bottom"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Colour"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Colour of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
; Horizontal alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Centre"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
|
||||
@@ -6,15 +6,24 @@
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-US/mod_mokojoomhero.ini
|
||||
; VERSION: 01.04.01
|
||||
; VERSION: 01.08.00
|
||||
; BRIEF: Language strings for MokoJoomHero module (en-US, frontend + admin form fields)
|
||||
|
||||
MOD_MOKOJOOMHERO_NO_CONTENT="Add content to this module to display it over the hero image."
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_LABEL="Content Source"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_DESC="Choose whether to enter content manually or pull from a Joomla article."
|
||||
MOD_MOKOJOOMHERO_SOURCE_MANUAL="Manual Editor"
|
||||
MOD_MOKOJOOMHERO_SOURCE_ARTICLE="Joomla Article"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_LABEL="Article"
|
||||
MOD_MOKOJOOMHERO_ARTICLE_DESC="Select a published article to use as the hero content. The article introtext (or fulltext) is displayed."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_SELECT="- Select Article -"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_LABEL="Use Article Title"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_DESC="Replace the module title with the selected article's title."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
@@ -27,6 +36,14 @@ MOD_MOKOJOOMHERO_MODE_LOCALVIDEO="Local Video"
|
||||
MOD_MOKOJOOMHERO_MODE_COLOR="Solid Color"
|
||||
MOD_MOKOJOOMHERO_MODE_GRADIENT="Gradient"
|
||||
|
||||
; Transition type
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_LABEL="Transition Type"
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_DESC="How images transition between slides."
|
||||
MOD_MOKOJOOMHERO_FADE_CROSSFADE="Crossfade"
|
||||
MOD_MOKOJOOMHERO_FADE_SLIDE="Slide"
|
||||
MOD_MOKOJOOMHERO_FADE_BLACK="Fade to Black"
|
||||
MOD_MOKOJOOMHERO_FADE_ZOOM="Zoom (Ken Burns)"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC="Path to folder containing hero images, relative to Joomla root (e.g. images/heroes)."
|
||||
@@ -35,6 +52,15 @@ MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slid
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Per-slide content
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_LABEL="Slide Content"
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_DESC="Define individual slides with unique images and content. When populated, this overrides the random image folder. Leave empty to use the folder-based slideshow."
|
||||
MOD_MOKOJOOMHERO_SLIDE_IMAGE_LABEL="Image"
|
||||
MOD_MOKOJOOMHERO_SLIDE_HEADING_LABEL="Heading"
|
||||
MOD_MOKOJOOMHERO_SLIDE_BODY_LABEL="Body Text"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_LABEL="Link URL"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_TEXT_LABEL="Link Text"
|
||||
|
||||
; Video settings (embedded)
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_LABEL="Video URL"
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects the source."
|
||||
@@ -64,22 +90,64 @@ MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_LABEL="Card Fade-in Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_DESC="Delay in milliseconds before the content card fades in. Set to 0 for no delay."
|
||||
|
||||
; Content animation
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_LABEL="Content Animation"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DESC="Entrance animation for the overlay content when the hero scrolls into view."
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_LABEL="Animation Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_DESC="Delay before the content animation starts."
|
||||
MOD_MOKOJOOMHERO_ANIM_NONE="None"
|
||||
MOD_MOKOJOOMHERO_ANIM_FADE_IN="Fade In"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_UP="Slide Up"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_LEFT="Slide from Right"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_RIGHT="Slide from Left"
|
||||
|
||||
; Parallax
|
||||
MOD_MOKOJOOMHERO_PARALLAX_LABEL="Parallax Effect"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_DESC="Background moves at a slower rate than page content on scroll, creating a depth effect."
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_LABEL="Parallax Speed"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_DESC="How much the background moves relative to scroll (0.1 = subtle, 0.9 = dramatic)."
|
||||
|
||||
; Video poster
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_LABEL="Video Poster Image"
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_DESC="Fallback image displayed while the video loads. Prevents a blank hero on slow connections."
|
||||
|
||||
; Scroll indicator
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_LABEL="Show Scroll Indicator"
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_DESC="Show an animated down-arrow at the bottom of the hero prompting users to scroll."
|
||||
|
||||
; Mute toggle
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL="Show Mute Toggle"
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC="Show a mute/unmute button on the hero video. Videos always start muted (required for autoplay)."
|
||||
|
||||
; Hero height (mobile)
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_LABEL="Mobile Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_DESC="Height of the hero on mobile devices. Leave empty for auto height. Uses the same units as Hero Height."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_HINT="e.g. 40vh or 300px (empty = auto)"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_LABEL="Overlay Type"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_DESC="How the overlay is applied. Solid fills evenly; gradient fades from transparent to opaque in the chosen direction."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_SOLID="Solid"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_BOTTOM="Gradient (dark at bottom)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_TOP="Gradient (dark at top)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_LEFT="Gradient (dark at left)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_RIGHT="Gradient (dark at right)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Color"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background color of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_VALIGN_LABEL="Vertical Alignment"
|
||||
MOD_MOKOJOOMHERO_VALIGN_DESC="Vertical position of the content within the hero."
|
||||
MOD_MOKOJOOMHERO_VALIGN_TOP="Top"
|
||||
MOD_MOKOJOOMHERO_VALIGN_CENTER="Center"
|
||||
MOD_MOKOJOOMHERO_VALIGN_BOTTOM="Bottom"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Color"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Color of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
; Horizontal alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Center"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-US/mod_mokojoomhero.sys.ini
|
||||
; VERSION: 01.04.01
|
||||
; VERSION: 01.08.00
|
||||
; BRIEF: System language strings — used in admin Extension Manager and Module Manager (en-US)
|
||||
|
||||
MOD_MOKOJOOMHERO="Module - MokoJoomHero"
|
||||
@@ -14,17 +14,36 @@ MOD_MOKOJOOMHERO_DESCRIPTION="Displays a random hero image slideshow or backgrou
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_LABEL="Content Source"
|
||||
MOD_MOKOJOOMHERO_CONTENT_SOURCE_DESC="Choose whether to enter content manually or pull from a Joomla article."
|
||||
MOD_MOKOJOOMHERO_SOURCE_MANUAL="Manual Editor"
|
||||
MOD_MOKOJOOMHERO_SOURCE_ARTICLE="Joomla Article"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_LABEL="Article"
|
||||
MOD_MOKOJOOMHERO_ARTICLE_DESC="Select a published article to use as the hero content."
|
||||
MOD_MOKOJOOMHERO_ARTICLE_SELECT="- Select Article -"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_LABEL="Use Article Title"
|
||||
MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_DESC="Replace the module title with the selected article's title."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
; Hero mode
|
||||
MOD_MOKOJOOMHERO_MODE_LABEL="Hero Mode"
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images, an embedded video (YouTube/Vimeo), or a local video file."
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images, an embedded video (YouTube/Vimeo), a local video file, a solid color, or a gradient."
|
||||
MOD_MOKOJOOMHERO_MODE_IMAGES="Images"
|
||||
MOD_MOKOJOOMHERO_MODE_VIDEO="Video (YouTube/Vimeo)"
|
||||
MOD_MOKOJOOMHERO_MODE_LOCALVIDEO="Local Video"
|
||||
MOD_MOKOJOOMHERO_MODE_COLOR="Solid Color"
|
||||
MOD_MOKOJOOMHERO_MODE_GRADIENT="Gradient"
|
||||
|
||||
; Transition type
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_LABEL="Transition Type"
|
||||
MOD_MOKOJOOMHERO_FADE_TYPE_DESC="How images transition between slides."
|
||||
MOD_MOKOJOOMHERO_FADE_CROSSFADE="Crossfade"
|
||||
MOD_MOKOJOOMHERO_FADE_SLIDE="Slide"
|
||||
MOD_MOKOJOOMHERO_FADE_BLACK="Fade to Black"
|
||||
MOD_MOKOJOOMHERO_FADE_ZOOM="Zoom (Ken Burns)"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
@@ -34,6 +53,15 @@ MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slid
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Per-slide content
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_LABEL="Slide Content"
|
||||
MOD_MOKOJOOMHERO_SLIDE_CONTENT_DESC="Define individual slides with unique images and content."
|
||||
MOD_MOKOJOOMHERO_SLIDE_IMAGE_LABEL="Image"
|
||||
MOD_MOKOJOOMHERO_SLIDE_HEADING_LABEL="Heading"
|
||||
MOD_MOKOJOOMHERO_SLIDE_BODY_LABEL="Body Text"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_LABEL="Link URL"
|
||||
MOD_MOKOJOOMHERO_SLIDE_LINK_TEXT_LABEL="Link Text"
|
||||
|
||||
; Video settings (embedded)
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_LABEL="Video URL"
|
||||
MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects the source."
|
||||
@@ -42,31 +70,85 @@ MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="YouTube or Vimeo URL. The module auto-detects
|
||||
MOD_MOKOJOOMHERO_LOCAL_VIDEO_LABEL="Video File"
|
||||
MOD_MOKOJOOMHERO_LOCAL_VIDEO_DESC="Select a video file from the Media Manager (mp4, webm, ogg)."
|
||||
|
||||
; Content animation
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_LABEL="Content Animation"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DESC="Entrance animation for the overlay content when the hero scrolls into view."
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_LABEL="Animation Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_DESC="Delay before the content animation starts."
|
||||
MOD_MOKOJOOMHERO_ANIM_NONE="None"
|
||||
MOD_MOKOJOOMHERO_ANIM_FADE_IN="Fade In"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_UP="Slide Up"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_LEFT="Slide from Right"
|
||||
MOD_MOKOJOOMHERO_ANIM_SLIDE_RIGHT="Slide from Left"
|
||||
|
||||
; Card delay
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_LABEL="Card Fade-in Delay (ms)"
|
||||
MOD_MOKOJOOMHERO_CARD_DELAY_DESC="Delay in milliseconds before the content card fades in. Set to 0 for no delay."
|
||||
|
||||
; Parallax
|
||||
MOD_MOKOJOOMHERO_PARALLAX_LABEL="Parallax Effect"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_DESC="Background moves at a slower rate than page content on scroll."
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_LABEL="Parallax Speed"
|
||||
MOD_MOKOJOOMHERO_PARALLAX_SPEED_DESC="How much the background moves relative to scroll (0.1 = subtle, 0.9 = dramatic)."
|
||||
|
||||
; Video poster
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_LABEL="Video Poster Image"
|
||||
MOD_MOKOJOOMHERO_VIDEO_POSTER_DESC="Fallback image displayed while the video loads."
|
||||
|
||||
; Scroll indicator
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_LABEL="Show Scroll Indicator"
|
||||
MOD_MOKOJOOMHERO_SCROLL_INDICATOR_DESC="Show an animated down-arrow at the bottom of the hero prompting users to scroll."
|
||||
|
||||
; Mute toggle
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL="Show Mute Toggle"
|
||||
MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC="Show a mute/unmute button on the hero video. Videos always start muted (required for autoplay)."
|
||||
|
||||
; Solid color background
|
||||
MOD_MOKOJOOMHERO_BG_COLOR_LABEL="Background Color"
|
||||
MOD_MOKOJOOMHERO_BG_COLOR_DESC="Solid background color for the hero section."
|
||||
|
||||
; Gradient background
|
||||
MOD_MOKOJOOMHERO_GRADIENT_START_LABEL="Gradient Start Color"
|
||||
MOD_MOKOJOOMHERO_GRADIENT_START_DESC="Starting color of the gradient."
|
||||
MOD_MOKOJOOMHERO_GRADIENT_END_LABEL="Gradient End Color"
|
||||
MOD_MOKOJOOMHERO_GRADIENT_END_DESC="Ending color of the gradient."
|
||||
MOD_MOKOJOOMHERO_GRADIENT_ANGLE_LABEL="Gradient Angle"
|
||||
MOD_MOKOJOOMHERO_GRADIENT_ANGLE_DESC="Direction of the gradient in degrees (0 = bottom to top, 90 = left to right, 135 = diagonal)."
|
||||
|
||||
; Hero height
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_LABEL="Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_DESC="Height of the hero section. Use px for fixed pixels (e.g. 400px) or vh for viewport height (e.g. 60vh for 60% of screen)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Hero height (mobile)
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_LABEL="Mobile Hero Height"
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_DESC="Height of the hero on mobile devices. Leave empty for auto height."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_HINT="e.g. 40vh or 300px (empty = auto)"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_LABEL="Overlay Type"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_TYPE_DESC="How the overlay is applied. Solid fills evenly; gradient fades from transparent to opaque in the chosen direction."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_SOLID="Solid"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_BOTTOM="Gradient (dark at bottom)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_TOP="Gradient (dark at top)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_LEFT="Gradient (dark at left)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_RIGHT="Gradient (dark at right)"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Color"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background color of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_VALIGN_LABEL="Vertical Alignment"
|
||||
MOD_MOKOJOOMHERO_VALIGN_DESC="Vertical position of the content within the hero."
|
||||
MOD_MOKOJOOMHERO_VALIGN_TOP="Top"
|
||||
MOD_MOKOJOOMHERO_VALIGN_CENTER="Center"
|
||||
MOD_MOKOJOOMHERO_VALIGN_BOTTOM="Bottom"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Color"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Color of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
; Horizontal alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Center"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
* DEFGROUP: MokoJoomHero.Module.Assets
|
||||
* INGROUP: MokoJoomHero.Module
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
* PATH: /src/css/template.css
|
||||
* VERSION: 01.04.01
|
||||
* BRIEF: Hero module stylesheet — slideshow, video background, overlay
|
||||
* PATH: /src/packages/mod_mokojoomhero/media/css/mod_mokojoomhero.css
|
||||
* VERSION: 01.08.00
|
||||
* BRIEF: Hero module stylesheet — slideshow, video, colour/gradient, overlay, card, mute toggle, responsive
|
||||
*/
|
||||
|
||||
/* ============================================================
|
||||
@@ -31,7 +31,7 @@
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Image slides
|
||||
Image slides — base
|
||||
============================================================ */
|
||||
.mokojoomhero__slide {
|
||||
position: absolute;
|
||||
@@ -40,13 +40,51 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
opacity: 0;
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
|
||||
.mokojoomhero__slide--active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ── Crossfade (default) ── */
|
||||
.mokojoomhero[data-transition="crossfade"] .mokojoomhero__slide {
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
|
||||
/* ── Slide ── */
|
||||
.mokojoomhero[data-transition="slide"] .mokojoomhero__slide {
|
||||
opacity: 1;
|
||||
transform: translateX(100%);
|
||||
transition: transform 0.8s ease;
|
||||
}
|
||||
|
||||
.mokojoomhero[data-transition="slide"] .mokojoomhero__slide--active {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.mokojoomhero[data-transition="slide"] .mokojoomhero__slide--exit {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
/* ── Fade to black ── */
|
||||
.mokojoomhero[data-transition="fade-black"] .mokojoomhero__slide {
|
||||
transition: opacity 0.6s ease;
|
||||
}
|
||||
|
||||
/* ── Zoom (Ken Burns) ── */
|
||||
.mokojoomhero[data-transition="zoom"] .mokojoomhero__slide {
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
|
||||
.mokojoomhero[data-transition="zoom"] .mokojoomhero__slide--active {
|
||||
animation: mokojoomhero-zoom 8s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes mokojoomhero-zoom {
|
||||
from { transform: scale(1); }
|
||||
to { transform: scale(1.08); }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Video background
|
||||
============================================================ */
|
||||
@@ -83,7 +121,6 @@ iframe.mokojoomhero__video {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -173,12 +210,147 @@ iframe.mokojoomhero__video {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Video poster image
|
||||
============================================================ */
|
||||
.mokojoomhero__poster {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Scroll-down indicator
|
||||
============================================================ */
|
||||
.mokojoomhero__scroll-indicator {
|
||||
position: absolute;
|
||||
bottom: 1.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 2;
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.3s;
|
||||
animation: mokojoomhero-bounce 2s infinite;
|
||||
}
|
||||
|
||||
.mokojoomhero__scroll-indicator:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.mokojoomhero__scroll-indicator--hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes mokojoomhero-bounce {
|
||||
0%, 20%, 50%, 80%, 100% { transform: translateX(-50%) translateY(0); }
|
||||
40% { transform: translateX(-50%) translateY(-8px); }
|
||||
60% { transform: translateX(-50%) translateY(-4px); }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Content entrance animations
|
||||
============================================================ */
|
||||
.mokojoomhero__content[class*="mokojoomhero__content--anim-"] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mokojoomhero__content--anim-fade-in.mokojoomhero__content--visible {
|
||||
animation: mokojoomhero-anim-fade-in 0.8s ease forwards;
|
||||
}
|
||||
|
||||
.mokojoomhero__content--anim-slide-up.mokojoomhero__content--visible {
|
||||
animation: mokojoomhero-anim-slide-up 0.8s ease forwards;
|
||||
}
|
||||
|
||||
.mokojoomhero__content--anim-slide-left.mokojoomhero__content--visible {
|
||||
animation: mokojoomhero-anim-slide-left 0.8s ease forwards;
|
||||
}
|
||||
|
||||
.mokojoomhero__content--anim-slide-right.mokojoomhero__content--visible {
|
||||
animation: mokojoomhero-anim-slide-right 0.8s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes mokojoomhero-anim-fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes mokojoomhero-anim-slide-up {
|
||||
from { opacity: 0; transform: translateY(30px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes mokojoomhero-anim-slide-left {
|
||||
from { opacity: 0; transform: translateX(30px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
}
|
||||
|
||||
@keyframes mokojoomhero-anim-slide-right {
|
||||
from { opacity: 0; transform: translateX(-30px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Parallax
|
||||
============================================================ */
|
||||
.mokojoomhero[data-parallax] .mokojoomhero__slide,
|
||||
.mokojoomhero[data-parallax] .mokojoomhero__color,
|
||||
.mokojoomhero[data-parallax] .mokojoomhero__poster,
|
||||
.mokojoomhero[data-parallax] video.mokojoomhero__video,
|
||||
.mokojoomhero[data-parallax] iframe.mokojoomhero__video {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Reduced motion — WCAG 2.1 AA (SC 2.3.3)
|
||||
============================================================ */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.mokojoomhero__slide {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
}
|
||||
|
||||
.mokojoomhero__card[data-card-delay] {
|
||||
opacity: 1;
|
||||
animation: none !important;
|
||||
}
|
||||
|
||||
.mokojoomhero__scroll-indicator {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.mokojoomhero[data-transition="zoom"] .mokojoomhero__slide--active {
|
||||
animation: none !important;
|
||||
}
|
||||
|
||||
.mokojoomhero__content[class*="mokojoomhero__content--anim-"] {
|
||||
opacity: 1;
|
||||
animation: none !important;
|
||||
}
|
||||
|
||||
.mokojoomhero[data-parallax] .mokojoomhero__slide,
|
||||
.mokojoomhero[data-parallax] .mokojoomhero__color,
|
||||
.mokojoomhero[data-parallax] .mokojoomhero__poster,
|
||||
.mokojoomhero[data-parallax] video.mokojoomhero__video,
|
||||
.mokojoomhero[data-parallax] iframe.mokojoomhero__video {
|
||||
will-change: auto;
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Responsive
|
||||
============================================================ */
|
||||
@media (max-width: 768px) {
|
||||
.mokojoomhero {
|
||||
height: auto !important;
|
||||
height: var(--mokojoomhero-mobile-height, auto) !important;
|
||||
}
|
||||
|
||||
.mokojoomhero__video,
|
||||
@@ -186,8 +358,17 @@ iframe.mokojoomhero__video {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Keep colour/gradient backgrounds visible on mobile */
|
||||
.mokojoomhero__color {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mokojoomhero__overlay {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Only clear overlay background when media is hidden (image/video modes) */
|
||||
.mokojoomhero:not(:has(.mokojoomhero__color)) .mokojoomhero__overlay {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
* DEFGROUP: MokoJoomHero.Module.Assets
|
||||
* INGROUP: MokoJoomHero.Module
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
* PATH: /src/js/template.js
|
||||
* VERSION: 01.04.01
|
||||
* BRIEF: Hero module JavaScript — image slideshow crossfade
|
||||
* PATH: /src/packages/mod_mokojoomhero/media/js/mod_mokojoomhero.js
|
||||
* VERSION: 01.08.00
|
||||
* BRIEF: Hero module JavaScript — slideshow crossfade, video viewport control, mute toggle
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
@@ -20,25 +20,114 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
return;
|
||||
}
|
||||
|
||||
var prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
// ── Image slideshow ──
|
||||
document.querySelectorAll('.mokojoomhero[data-slides]').forEach(function (hero) {
|
||||
var slides = hero.querySelectorAll('.mokojoomhero__slide');
|
||||
var interval = parseInt(hero.dataset.interval, 10) || 5000;
|
||||
var current = 0;
|
||||
var slides = hero.querySelectorAll('.mokojoomhero__slide');
|
||||
var interval = parseInt(hero.dataset.interval, 10) || 5000;
|
||||
var transition = hero.dataset.transition || 'crossfade';
|
||||
var current = 0;
|
||||
|
||||
if (slides.length < 2) {
|
||||
// Per-slide content data
|
||||
var slideContentData = null;
|
||||
var contentEl = hero.querySelector('.mokojoomhero__content');
|
||||
|
||||
if (hero.dataset.slideContent) {
|
||||
try {
|
||||
slideContentData = JSON.parse(hero.dataset.slideContent);
|
||||
} catch (e) {
|
||||
console.warn('MokoJoomHero: Failed to parse slide content data:', e.message);
|
||||
slideContentData = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (slides.length < 2 || prefersReducedMotion) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInterval(function () {
|
||||
slides[current].classList.remove('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'true');
|
||||
function updateSlideContent(index) {
|
||||
if (!slideContentData || !slideContentData[index] || !contentEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data = slideContentData[index];
|
||||
var card = contentEl.querySelector('.mokojoomhero__card');
|
||||
var target = card || contentEl;
|
||||
|
||||
// Clear existing content safely
|
||||
while (target.firstChild) {
|
||||
target.removeChild(target.firstChild);
|
||||
}
|
||||
|
||||
if (data.heading) {
|
||||
var h2 = document.createElement('h2');
|
||||
h2.className = 'mokojoomhero__title';
|
||||
h2.textContent = data.heading;
|
||||
target.appendChild(h2);
|
||||
}
|
||||
|
||||
if (data.body) {
|
||||
var p = document.createElement('p');
|
||||
p.textContent = data.body;
|
||||
target.appendChild(p);
|
||||
}
|
||||
|
||||
if (data.link && data.linkText) {
|
||||
var linkP = document.createElement('p');
|
||||
var a = document.createElement('a');
|
||||
a.href = data.link;
|
||||
a.className = 'btn btn-primary';
|
||||
a.textContent = data.linkText;
|
||||
linkP.appendChild(a);
|
||||
target.appendChild(linkP);
|
||||
}
|
||||
}
|
||||
|
||||
function advanceSlide() {
|
||||
var prev = current;
|
||||
current = (current + 1) % slides.length;
|
||||
|
||||
slides[current].classList.add('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'false');
|
||||
}, interval);
|
||||
if (transition === 'slide') {
|
||||
slides[prev].classList.add('mokojoomhero__slide--exit');
|
||||
slides[prev].classList.remove('mokojoomhero__slide--active');
|
||||
slides[prev].setAttribute('aria-hidden', 'true');
|
||||
|
||||
slides[current].classList.add('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'false');
|
||||
|
||||
// Reset exiting slide after transition completes
|
||||
setTimeout(function () {
|
||||
slides[prev].classList.remove('mokojoomhero__slide--exit');
|
||||
}, 800);
|
||||
|
||||
} else if (transition === 'fade-black') {
|
||||
// Phase 1: fade out current
|
||||
slides[prev].classList.remove('mokojoomhero__slide--active');
|
||||
slides[prev].setAttribute('aria-hidden', 'true');
|
||||
|
||||
// Phase 2: fade in next after a brief black gap
|
||||
setTimeout(function () {
|
||||
slides[current].classList.add('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'false');
|
||||
}, 600);
|
||||
|
||||
} else {
|
||||
// Crossfade and zoom use the same JS logic
|
||||
slides[prev].classList.remove('mokojoomhero__slide--active');
|
||||
slides[prev].setAttribute('aria-hidden', 'true');
|
||||
|
||||
slides[current].classList.add('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'false');
|
||||
}
|
||||
|
||||
updateSlideContent(current);
|
||||
}
|
||||
|
||||
// Set initial slide content
|
||||
updateSlideContent(0);
|
||||
|
||||
setInterval(advanceSlide, interval);
|
||||
});
|
||||
|
||||
// ── Pause/resume videos when out of viewport ──
|
||||
@@ -55,9 +144,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (entry.isIntersecting) {
|
||||
// Resume
|
||||
if (video) {
|
||||
video.play();
|
||||
var playPromise = video.play();
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(function () {
|
||||
// Autoplay blocked by browser policy — not actionable
|
||||
});
|
||||
}
|
||||
}
|
||||
if (iframe) {
|
||||
if (iframe && iframe.contentWindow) {
|
||||
var src = iframe.src || '';
|
||||
if (src.indexOf('youtube') !== -1) {
|
||||
iframe.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
|
||||
@@ -70,7 +164,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (video) {
|
||||
video.pause();
|
||||
}
|
||||
if (iframe) {
|
||||
if (iframe && iframe.contentWindow) {
|
||||
var src = iframe.src || '';
|
||||
if (src.indexOf('youtube') !== -1) {
|
||||
iframe.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
|
||||
@@ -86,9 +180,92 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
observer.observe(hero);
|
||||
});
|
||||
|
||||
// ── Content entrance animations ──
|
||||
if (!prefersReducedMotion) {
|
||||
var animObserver = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('mokojoomhero__content--visible');
|
||||
animObserver.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.2 });
|
||||
|
||||
document.querySelectorAll('.mokojoomhero__content[class*="mokojoomhero__content--anim-"]').forEach(function (el) {
|
||||
animObserver.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
// ── Parallax scroll ──
|
||||
if (!prefersReducedMotion) {
|
||||
var parallaxHeroes = document.querySelectorAll('.mokojoomhero[data-parallax]');
|
||||
|
||||
if (parallaxHeroes.length) {
|
||||
var onScroll = function () {
|
||||
parallaxHeroes.forEach(function (hero) {
|
||||
var rect = hero.getBoundingClientRect();
|
||||
var speed = parseFloat(hero.dataset.parallax) || 0.5;
|
||||
|
||||
if (rect.bottom > 0 && rect.top < window.innerHeight) {
|
||||
var offset = Math.round(rect.top * speed * -1);
|
||||
var bg = hero.querySelector('.mokojoomhero__slide, .mokojoomhero__color, .mokojoomhero__poster, video.mokojoomhero__video');
|
||||
|
||||
if (bg) {
|
||||
bg.style.transform = 'translateY(' + offset + 'px)';
|
||||
}
|
||||
|
||||
var iframe = hero.querySelector('iframe.mokojoomhero__video');
|
||||
|
||||
if (iframe) {
|
||||
iframe.style.transform = 'translate(-50%, calc(-50% + ' + offset + 'px))';
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
onScroll();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Scroll-down indicator ──
|
||||
document.querySelectorAll('.mokojoomhero__scroll-indicator').forEach(function (btn) {
|
||||
var hero = btn.closest('.mokojoomhero');
|
||||
|
||||
if (!hero) {
|
||||
return;
|
||||
}
|
||||
|
||||
btn.addEventListener('click', function () {
|
||||
var nextEl = hero.nextElementSibling || hero.parentElement.nextElementSibling;
|
||||
|
||||
if (nextEl) {
|
||||
nextEl.scrollIntoView({ behavior: prefersReducedMotion ? 'auto' : 'smooth' });
|
||||
}
|
||||
});
|
||||
|
||||
// Hide indicator once hero scrolls out of view
|
||||
var scrollObserver = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) {
|
||||
btn.classList.add('mokojoomhero__scroll-indicator--hidden');
|
||||
} else {
|
||||
btn.classList.remove('mokojoomhero__scroll-indicator--hidden');
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
|
||||
scrollObserver.observe(hero);
|
||||
});
|
||||
|
||||
// ── Mute/unmute toggle ──
|
||||
document.querySelectorAll('.mokojoomhero__mute-toggle').forEach(function (btn) {
|
||||
var hero = btn.closest('.mokojoomhero');
|
||||
var hero = btn.closest('.mokojoomhero');
|
||||
|
||||
if (!hero) {
|
||||
return;
|
||||
}
|
||||
|
||||
var video = hero.querySelector('video.mokojoomhero__video');
|
||||
var iframe = hero.querySelector('iframe.mokojoomhero__video');
|
||||
var icon = btn.querySelector('.mokojoomhero__mute-icon');
|
||||
@@ -99,7 +276,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (video) {
|
||||
video.muted = !muted;
|
||||
}
|
||||
if (iframe) {
|
||||
if (iframe && iframe.contentWindow) {
|
||||
var src = iframe.src || '';
|
||||
if (src.indexOf('youtube') !== -1) {
|
||||
var func = muted ? 'unMute' : 'mute';
|
||||
@@ -112,7 +289,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
btn.setAttribute('data-muted', muted ? 'false' : 'true');
|
||||
btn.setAttribute('aria-label', muted ? 'Mute video' : 'Unmute video');
|
||||
icon.textContent = muted ? '\u{1F50A}' : '\u{1F507}';
|
||||
|
||||
if (icon) {
|
||||
icon.textContent = muted ? '\u{1F50A}' : '\u{1F507}';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,19 +6,14 @@
|
||||
*
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GPL-3.0-or-later
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Helper\ModuleHelper;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
// Require the system plugin to be installed and enabled
|
||||
if (!PluginHelper::isEnabled('system', 'mokojoomhero')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Joomla\CMS\Application\SiteApplication $app */
|
||||
/** @var \stdClass $module */
|
||||
/** @var \Joomla\Registry\Registry $params */
|
||||
@@ -33,47 +28,129 @@ $heroMode = $params->get('heroMode', 'images');
|
||||
$imageFolder = $params->get('imageFolder', 'images/heroes');
|
||||
$imageCount = (int) $params->get('imageCount', 5);
|
||||
$slideInterval = (int) $params->get('slideInterval', 5000);
|
||||
$fadeType = $params->get('fadeType', 'crossfade');
|
||||
$videoFile = $params->get('videoFile', '');
|
||||
$heroHeight = $params->get('heroHeight', '60vh');
|
||||
$heroHeightMobile = $params->get('heroHeightMobile', '');
|
||||
$overlayColor = $params->get('overlayColor', '#000000');
|
||||
$overlayType = $params->get('overlayType', 'solid');
|
||||
$overlayOpacity = (float) $params->get('overlayOpacity', 0.5);
|
||||
$textAlign = $params->get('textAlign', 'center');
|
||||
$verticalAlign = $params->get('verticalAlign', 'center');
|
||||
$textColor = $params->get('textColor', '#ffffff');
|
||||
$heroContent = $params->get('heroContent', '');
|
||||
$contentSource = $params->get('contentSource', 'manual');
|
||||
$articleId = (int) $params->get('articleId', 0);
|
||||
$useArticleTitle = (bool) $params->get('useArticleTitle', 0);
|
||||
$heroContent = $params->get('heroContent', '');
|
||||
$slideContent = $params->get('slideContent', '');
|
||||
$showCard = (bool) $params->get('showCard', 1);
|
||||
$cardDelay = (int) $params->get('cardDelay', 0);
|
||||
$showMuteToggle = (bool) $params->get('showMuteToggle', 0);
|
||||
$localVideoFile = $params->get('localVideoFile', '');
|
||||
$contentAnimation = $params->get('contentAnimation', 'none');
|
||||
$contentAnimationDelay = (int) $params->get('contentAnimationDelay', 0);
|
||||
$parallaxEnabled = (bool) $params->get('parallaxEnabled', 0);
|
||||
$parallaxSpeed = (float) $params->get('parallaxSpeed', 0.5);
|
||||
$showMuteToggle = (bool) $params->get('showMuteToggle', 0);
|
||||
$videoPoster = $params->get('videoPoster', '');
|
||||
$showScrollIndicator = (bool) $params->get('showScrollIndicator', 0);
|
||||
$localVideoFile = $params->get('localVideoFile', '');
|
||||
$bgColor = $params->get('bgColor', '#003366');
|
||||
$gradientStart = $params->get('gradientStart', '#003366');
|
||||
$gradientEnd = $params->get('gradientEnd', '#006699');
|
||||
$gradientAngle = (int) $params->get('gradientAngle', 135);
|
||||
|
||||
// Validate CSS height values to prevent injection
|
||||
if (!preg_match('/^\d+(\.\d+)?(px|vh|vw|em|rem|%)$/', $heroHeight)) {
|
||||
$heroHeight = '60vh';
|
||||
}
|
||||
|
||||
if ($heroHeightMobile && !preg_match('/^\d+(\.\d+)?(px|vh|vw|em|rem|%)$/', $heroHeightMobile)) {
|
||||
$heroHeightMobile = '';
|
||||
}
|
||||
|
||||
// Validate hex colour values
|
||||
$hexColorPattern = '/^#[0-9a-fA-F]{6}$/';
|
||||
|
||||
if (!preg_match($hexColorPattern, $overlayColor)) {
|
||||
$overlayColor = '#000000';
|
||||
}
|
||||
|
||||
if (!preg_match($hexColorPattern, $textColor)) {
|
||||
$textColor = '#ffffff';
|
||||
}
|
||||
|
||||
if (!preg_match($hexColorPattern, $bgColor)) {
|
||||
$bgColor = '#003366';
|
||||
}
|
||||
|
||||
if (!preg_match($hexColorPattern, $gradientStart)) {
|
||||
$gradientStart = '#003366';
|
||||
}
|
||||
|
||||
if (!preg_match($hexColorPattern, $gradientEnd)) {
|
||||
$gradientEnd = '#006699';
|
||||
}
|
||||
|
||||
// Validate allowlist values
|
||||
$allowedTextAlign = ['left', 'center', 'right'];
|
||||
|
||||
if (!in_array($textAlign, $allowedTextAlign, true)) {
|
||||
$textAlign = 'center';
|
||||
}
|
||||
|
||||
$allowedFadeTypes = ['crossfade', 'slide', 'fade-black', 'zoom'];
|
||||
|
||||
if (!in_array($fadeType, $allowedFadeTypes, true)) {
|
||||
$fadeType = 'crossfade';
|
||||
}
|
||||
|
||||
$allowedOverlayTypes = ['solid', 'gradient-bottom', 'gradient-top', 'gradient-left', 'gradient-right'];
|
||||
|
||||
if (!in_array($overlayType, $allowedOverlayTypes, true)) {
|
||||
$overlayType = 'solid';
|
||||
}
|
||||
|
||||
$allowedContentAnimations = ['none', 'fade-in', 'slide-up', 'slide-left', 'slide-right'];
|
||||
|
||||
if (!in_array($contentAnimation, $allowedContentAnimations, true)) {
|
||||
$contentAnimation = 'none';
|
||||
}
|
||||
|
||||
$parallaxSpeed = max(0.1, min(0.9, $parallaxSpeed));
|
||||
$gradientAngle = max(0, min(360, $gradientAngle));
|
||||
|
||||
// Collect hero images
|
||||
$heroImages = [];
|
||||
|
||||
if ($heroMode === 'images') {
|
||||
$folderPath = JPATH_ROOT . '/' . ltrim($imageFolder, '/');
|
||||
$folderPath = JPATH_ROOT . '/' . ltrim($imageFolder, '/');
|
||||
|
||||
if (is_dir($folderPath)) {
|
||||
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg'];
|
||||
$all = [];
|
||||
if (is_dir($folderPath)) {
|
||||
try {
|
||||
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg'];
|
||||
$all = [];
|
||||
|
||||
foreach (new DirectoryIterator($folderPath) as $file) {
|
||||
if ($file->isFile() && in_array(strtolower($file->getExtension()), $allowed, true)) {
|
||||
$all[] = $file->getFilename();
|
||||
}
|
||||
}
|
||||
foreach (new DirectoryIterator($folderPath) as $file) {
|
||||
if ($file->isFile() && in_array(strtolower($file->getExtension()), $allowed, true)) {
|
||||
$all[] = $file->getFilename();
|
||||
}
|
||||
}
|
||||
|
||||
if ($all) {
|
||||
shuffle($all);
|
||||
$picked = array_slice($all, 0, min($imageCount, 5));
|
||||
if ($all) {
|
||||
shuffle($all);
|
||||
$picked = array_slice($all, 0, min($imageCount, 5));
|
||||
|
||||
foreach ($picked as $filename) {
|
||||
$heroImages[] = Uri::root() . $imageFolder . '/' . $filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($picked as $filename) {
|
||||
$heroImages[] = Uri::root() . $imageFolder . '/' . $filename;
|
||||
}
|
||||
}
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
\Joomla\CMS\Log\Log::add(
|
||||
'MokoJoomHero: Cannot read image folder "' . $folderPath . '": ' . $e->getMessage(),
|
||||
\Joomla\CMS\Log\Log::WARNING,
|
||||
'mod_mokojoomhero'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build video URL — smartly detect YouTube, Vimeo, or local/direct file
|
||||
@@ -82,23 +159,84 @@ $youtubeId = '';
|
||||
$vimeoId = '';
|
||||
|
||||
if ($heroMode === 'localvideo' && $localVideoFile) {
|
||||
$videoUrl = Uri::root() . ltrim($localVideoFile, '/');
|
||||
$videoUrl = Uri::root() . ltrim($localVideoFile, '/');
|
||||
} elseif ($heroMode === 'video' && $videoFile) {
|
||||
// YouTube: watch, embed, shorts, youtu.be, with optional timestamps/params
|
||||
if (preg_match('/(?:youtube\.com\/(?:watch\?.*v=|embed\/|shorts\/|v\/)|youtu\.be\/)([\w-]{11})/', $videoFile, $m)) {
|
||||
$youtubeId = $m[1];
|
||||
// Vimeo: vimeo.com/123456 or player.vimeo.com/video/123456
|
||||
} elseif (preg_match('/vimeo\.com\/(?:video\/)?(\d+)/', $videoFile, $m)) {
|
||||
$vimeoId = $m[1];
|
||||
} else {
|
||||
// Direct URL or local file path
|
||||
$videoUrl = (strpos($videoFile, '://') !== false)
|
||||
? $videoFile
|
||||
: Uri::root() . ltrim($videoFile, '/');
|
||||
}
|
||||
// YouTube: watch, embed, shorts, youtu.be, with optional timestamps/params
|
||||
if (preg_match('/(?:youtube\.com\/(?:watch\?.*v=|embed\/|shorts\/|v\/)|youtu\.be\/)([\w-]{11})/', $videoFile, $m)) {
|
||||
$youtubeId = $m[1];
|
||||
// Vimeo: vimeo.com/123456 or player.vimeo.com/video/123456
|
||||
} elseif (preg_match('/vimeo\.com\/(?:video\/)?(\d+)/', $videoFile, $m)) {
|
||||
$vimeoId = $m[1];
|
||||
} else {
|
||||
// Direct URL or local file path
|
||||
$videoUrl = (strpos($videoFile, '://') !== false)
|
||||
? $videoFile
|
||||
: Uri::root() . ltrim($videoFile, '/');
|
||||
}
|
||||
}
|
||||
|
||||
// Module content from the editor (overlay text)
|
||||
$content = $module->content ?? '';
|
||||
// Load content from article if configured
|
||||
$articleTitle = '';
|
||||
|
||||
if ($contentSource === 'article' && $articleId > 0) {
|
||||
try {
|
||||
$db = \Joomla\CMS\Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName(['title', 'introtext', 'fulltext']))
|
||||
->from($db->quoteName('#__content'))
|
||||
->where($db->quoteName('id') . ' = ' . $articleId)
|
||||
->where($db->quoteName('state') . ' = 1');
|
||||
$db->setQuery($query);
|
||||
$article = $db->loadObject();
|
||||
|
||||
if ($article) {
|
||||
$rawContent = $article->introtext ?: $article->fulltext;
|
||||
$heroContent = \Joomla\CMS\HTML\HTMLHelper::_('content.prepare', $rawContent);
|
||||
$articleTitle = $article->title;
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
\Joomla\CMS\Log\Log::add(
|
||||
'MokoJoomHero: Failed to load article ID ' . $articleId . ': ' . $e->getMessage(),
|
||||
\Joomla\CMS\Log\Log::WARNING,
|
||||
'mod_mokojoomhero'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Process per-slide content — overrides folder-based images when populated
|
||||
$slides = [];
|
||||
|
||||
if ($heroMode === 'images' && !empty($slideContent)) {
|
||||
$slideData = is_string($slideContent) ? json_decode($slideContent, true) : (array) $slideContent;
|
||||
|
||||
if ($slideData === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||
\Joomla\CMS\Log\Log::add(
|
||||
'MokoJoomHero: Failed to decode slideContent JSON: ' . json_last_error_msg(),
|
||||
\Joomla\CMS\Log\Log::WARNING,
|
||||
'mod_mokojoomhero'
|
||||
);
|
||||
}
|
||||
|
||||
if (is_array($slideData)) {
|
||||
foreach ($slideData as $item) {
|
||||
$item = (array) $item;
|
||||
|
||||
if (!empty($item['image'])) {
|
||||
$slides[] = [
|
||||
'image' => Uri::root() . ltrim($item['image'], '/'),
|
||||
'heading' => $item['heading'] ?? '',
|
||||
'body' => $item['body'] ?? '',
|
||||
'link' => $item['link'] ?? '',
|
||||
'linkText' => $item['linkText'] ?? 'Learn More',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Per-slide content overrides folder-based random images
|
||||
if ($slides) {
|
||||
$heroImages = array_column($slides, 'image');
|
||||
}
|
||||
}
|
||||
|
||||
require ModuleHelper::getLayoutPath('mod_mokojoomhero', $params->get('layout', 'default'));
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
DEFGROUP: MokoJoomHero.Module
|
||||
INGROUP: MokoJoomHero
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
PATH: /src/mod_mokojoomhero.xml
|
||||
PATH: /src/packages/mod_mokojoomhero/mod_mokojoomhero.xml
|
||||
VERSION: 01.00.20
|
||||
BRIEF: Joomla module manifest — random hero image with content overlay
|
||||
-->
|
||||
@@ -22,7 +22,7 @@
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<version>01.04.01-dev</version>
|
||||
<version>01.08.00-rc</version>
|
||||
<description>Displays a random hero image slideshow or background video with content overlaid. Designed for MokoOnyx template. By Moko Consulting.</description>
|
||||
|
||||
<scriptfile>script.php</scriptfile>
|
||||
@@ -99,6 +99,19 @@
|
||||
step="15"
|
||||
showon="heroMode:gradient"
|
||||
/>
|
||||
<field
|
||||
name="fadeType"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_FADE_TYPE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_FADE_TYPE_DESC"
|
||||
default="crossfade"
|
||||
showon="heroMode:images"
|
||||
>
|
||||
<option value="crossfade">MOD_MOKOJOOMHERO_FADE_CROSSFADE</option>
|
||||
<option value="slide">MOD_MOKOJOOMHERO_FADE_SLIDE</option>
|
||||
<option value="fade-black">MOD_MOKOJOOMHERO_FADE_BLACK</option>
|
||||
<option value="zoom">MOD_MOKOJOOMHERO_FADE_ZOOM</option>
|
||||
</field>
|
||||
<field
|
||||
name="imageFolder"
|
||||
type="text"
|
||||
@@ -128,6 +141,51 @@
|
||||
step="500"
|
||||
showon="heroMode:images"
|
||||
/>
|
||||
<field
|
||||
name="slideContent"
|
||||
type="subform"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_CONTENT_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_SLIDE_CONTENT_DESC"
|
||||
multiple="true"
|
||||
layout="joomla.form.field.subform.repeatable-table"
|
||||
showon="heroMode:images"
|
||||
max="5"
|
||||
>
|
||||
<form>
|
||||
<field
|
||||
name="image"
|
||||
type="media"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_IMAGE_LABEL"
|
||||
types="images"
|
||||
/>
|
||||
<field
|
||||
name="heading"
|
||||
type="text"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_HEADING_LABEL"
|
||||
filter="string"
|
||||
/>
|
||||
<field
|
||||
name="body"
|
||||
type="textarea"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_BODY_LABEL"
|
||||
filter="safehtml"
|
||||
rows="3"
|
||||
/>
|
||||
<field
|
||||
name="link"
|
||||
type="url"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_LINK_LABEL"
|
||||
filter="url"
|
||||
/>
|
||||
<field
|
||||
name="linkText"
|
||||
type="text"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_LINK_TEXT_LABEL"
|
||||
filter="string"
|
||||
default="Learn More"
|
||||
/>
|
||||
</form>
|
||||
</field>
|
||||
<field
|
||||
name="videoFile"
|
||||
type="text"
|
||||
@@ -153,6 +211,56 @@
|
||||
default="60vh"
|
||||
filter="string"
|
||||
/>
|
||||
<field
|
||||
name="heroHeightMobile"
|
||||
type="text"
|
||||
label="MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_DESC"
|
||||
hint="MOD_MOKOJOOMHERO_HERO_HEIGHT_MOBILE_HINT"
|
||||
default=""
|
||||
filter="string"
|
||||
/>
|
||||
<field
|
||||
name="videoPoster"
|
||||
type="media"
|
||||
label="MOD_MOKOJOOMHERO_VIDEO_POSTER_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_VIDEO_POSTER_DESC"
|
||||
types="images"
|
||||
showon="heroMode:video,localvideo"
|
||||
/>
|
||||
<field
|
||||
name="showScrollIndicator"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="MOD_MOKOJOOMHERO_SCROLL_INDICATOR_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_SCROLL_INDICATOR_DESC"
|
||||
default="0"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="parallaxEnabled"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="MOD_MOKOJOOMHERO_PARALLAX_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_PARALLAX_DESC"
|
||||
default="0"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="parallaxSpeed"
|
||||
type="range"
|
||||
label="MOD_MOKOJOOMHERO_PARALLAX_SPEED_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_PARALLAX_SPEED_DESC"
|
||||
default="0.5"
|
||||
min="0.1"
|
||||
max="0.9"
|
||||
step="0.1"
|
||||
showon="parallaxEnabled:1"
|
||||
/>
|
||||
<field
|
||||
name="showMuteToggle"
|
||||
type="radio"
|
||||
@@ -169,6 +277,16 @@
|
||||
<fieldset name="content"
|
||||
label="MOD_MOKOJOOMHERO_FIELDSET_CONTENT"
|
||||
>
|
||||
<field
|
||||
name="contentSource"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_CONTENT_SOURCE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_CONTENT_SOURCE_DESC"
|
||||
default="manual"
|
||||
>
|
||||
<option value="manual">MOD_MOKOJOOMHERO_SOURCE_MANUAL</option>
|
||||
<option value="article">MOD_MOKOJOOMHERO_SOURCE_ARTICLE</option>
|
||||
</field>
|
||||
<field
|
||||
name="heroContent"
|
||||
type="editor"
|
||||
@@ -177,7 +295,31 @@
|
||||
filter="safehtml"
|
||||
buttons="true"
|
||||
hide="readmore,pagebreak"
|
||||
showon="contentSource:manual"
|
||||
/>
|
||||
<field
|
||||
name="articleId"
|
||||
type="sql"
|
||||
label="MOD_MOKOJOOMHERO_ARTICLE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_ARTICLE_DESC"
|
||||
query="SELECT id, title FROM #__content WHERE state = 1 ORDER BY title ASC"
|
||||
key_field="id"
|
||||
value_field="title"
|
||||
header="MOD_MOKOJOOMHERO_ARTICLE_SELECT"
|
||||
showon="contentSource:article"
|
||||
/>
|
||||
<field
|
||||
name="useArticleTitle"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_USE_ARTICLE_TITLE_DESC"
|
||||
default="0"
|
||||
showon="contentSource:article"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="showCard"
|
||||
type="radio"
|
||||
@@ -189,6 +331,30 @@
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="contentAnimation"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_CONTENT_ANIM_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_CONTENT_ANIM_DESC"
|
||||
default="none"
|
||||
>
|
||||
<option value="none">MOD_MOKOJOOMHERO_ANIM_NONE</option>
|
||||
<option value="fade-in">MOD_MOKOJOOMHERO_ANIM_FADE_IN</option>
|
||||
<option value="slide-up">MOD_MOKOJOOMHERO_ANIM_SLIDE_UP</option>
|
||||
<option value="slide-left">MOD_MOKOJOOMHERO_ANIM_SLIDE_LEFT</option>
|
||||
<option value="slide-right">MOD_MOKOJOOMHERO_ANIM_SLIDE_RIGHT</option>
|
||||
</field>
|
||||
<field
|
||||
name="contentAnimationDelay"
|
||||
type="number"
|
||||
label="MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_CONTENT_ANIM_DELAY_DESC"
|
||||
default="0"
|
||||
min="0"
|
||||
max="3000"
|
||||
step="100"
|
||||
showon="contentAnimation!:none"
|
||||
/>
|
||||
<field
|
||||
name="cardDelay"
|
||||
type="number"
|
||||
@@ -211,6 +377,19 @@
|
||||
description="MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC"
|
||||
default="#000000"
|
||||
/>
|
||||
<field
|
||||
name="overlayType"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_OVERLAY_TYPE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_OVERLAY_TYPE_DESC"
|
||||
default="solid"
|
||||
>
|
||||
<option value="solid">MOD_MOKOJOOMHERO_OVERLAY_SOLID</option>
|
||||
<option value="gradient-bottom">MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_BOTTOM</option>
|
||||
<option value="gradient-top">MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_TOP</option>
|
||||
<option value="gradient-left">MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_LEFT</option>
|
||||
<option value="gradient-right">MOD_MOKOJOOMHERO_OVERLAY_GRADIENT_RIGHT</option>
|
||||
</field>
|
||||
<field
|
||||
name="overlayOpacity"
|
||||
type="range"
|
||||
@@ -232,6 +411,17 @@
|
||||
<option value="center">MOD_MOKOJOOMHERO_ALIGN_CENTER</option>
|
||||
<option value="right">MOD_MOKOJOOMHERO_ALIGN_RIGHT</option>
|
||||
</field>
|
||||
<field
|
||||
name="verticalAlign"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_VALIGN_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_VALIGN_DESC"
|
||||
default="center"
|
||||
>
|
||||
<option value="top">MOD_MOKOJOOMHERO_VALIGN_TOP</option>
|
||||
<option value="center">MOD_MOKOJOOMHERO_VALIGN_CENTER</option>
|
||||
<option value="bottom">MOD_MOKOJOOMHERO_VALIGN_BOTTOM</option>
|
||||
</field>
|
||||
<field
|
||||
name="textColor"
|
||||
type="color"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GPL-3.0-or-later
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
@@ -6,47 +6,89 @@
|
||||
*
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GPL-3.0-or-later
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/** @var string $heroMode */
|
||||
/** @var array $heroImages */
|
||||
/** @var int $slideInterval */
|
||||
/** @var string $fadeType */
|
||||
/** @var string $videoUrl */
|
||||
/** @var string $youtubeId */
|
||||
/** @var string $vimeoId */
|
||||
/** @var string $heroHeight */
|
||||
/** @var string $heroHeightMobile */
|
||||
/** @var string $overlayColor */
|
||||
/** @var string $overlayType */
|
||||
/** @var float $overlayOpacity */
|
||||
/** @var string $textAlign */
|
||||
/** @var string $verticalAlign */
|
||||
/** @var string $textColor */
|
||||
/** @var string $contentSource */
|
||||
/** @var int $articleId */
|
||||
/** @var bool $useArticleTitle */
|
||||
/** @var string $heroContent */
|
||||
/** @var string $articleTitle */
|
||||
/** @var array $slides */
|
||||
/** @var bool $showCard */
|
||||
/** @var int $cardDelay */
|
||||
/** @var string $contentAnimation */
|
||||
/** @var int $contentAnimationDelay */
|
||||
/** @var bool $parallaxEnabled */
|
||||
/** @var float $parallaxSpeed */
|
||||
/** @var bool $showMuteToggle */
|
||||
/** @var string $videoPoster */
|
||||
/** @var bool $showScrollIndicator */
|
||||
/** @var string $bgColor */
|
||||
/** @var string $gradientStart */
|
||||
/** @var string $gradientEnd */
|
||||
/** @var int $gradientAngle */
|
||||
/** @var string $content */
|
||||
|
||||
$moduleId = 'mod-mokojoomhero-' . $module->id;
|
||||
|
||||
// Convert hex overlay colour to rgba
|
||||
$r = hexdec(substr($overlayColor, 1, 2));
|
||||
$g = hexdec(substr($overlayColor, 3, 2));
|
||||
$b = hexdec(substr($overlayColor, 5, 2));
|
||||
$rgba = "rgba($r, $g, $b, $overlayOpacity)";
|
||||
$rgbaOpaque = "rgba($r, $g, $b, $overlayOpacity)";
|
||||
$rgbaTransparent = "rgba($r, $g, $b, 0)";
|
||||
|
||||
// Build overlay background based on type
|
||||
$overlayDirections = [
|
||||
'gradient-bottom' => 'to bottom',
|
||||
'gradient-top' => 'to top',
|
||||
'gradient-left' => 'to left',
|
||||
'gradient-right' => 'to right',
|
||||
];
|
||||
|
||||
if ($overlayType !== 'solid' && isset($overlayDirections[$overlayType])) {
|
||||
$dir = $overlayDirections[$overlayType];
|
||||
$overlayBg = "background: linear-gradient($dir, $rgbaTransparent, $rgbaOpaque);";
|
||||
} else {
|
||||
$overlayBg = "background-color: $rgbaOpaque;";
|
||||
}
|
||||
|
||||
// Map vertical alignment to CSS align-items
|
||||
$valignMap = ['top' => 'flex-start', 'center' => 'center', 'bottom' => 'flex-end'];
|
||||
$valignCss = $valignMap[$verticalAlign] ?? 'center';
|
||||
|
||||
$heightAttr = htmlspecialchars($heroHeight, ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<?php if ($heroHeightMobile) : ?>
|
||||
<style>#<?php echo $moduleId; ?> { --mokojoomhero-mobile-height: <?php echo htmlspecialchars($heroHeightMobile, ENT_QUOTES, 'UTF-8'); ?>; }</style>
|
||||
<?php endif; ?>
|
||||
<div id="<?php echo $moduleId; ?>" class="mokojoomhero" style="height: <?php echo $heightAttr; ?>;"
|
||||
<?php if ($parallaxEnabled) : ?>
|
||||
data-parallax="<?php echo $parallaxSpeed; ?>"
|
||||
<?php endif; ?>
|
||||
<?php if ($heroMode === 'images' && count($heroImages) > 1) : ?>
|
||||
data-slides="<?php echo htmlspecialchars(json_encode($heroImages), ENT_QUOTES, 'UTF-8'); ?>"
|
||||
data-interval="<?php echo $slideInterval; ?>"
|
||||
data-transition="<?php echo htmlspecialchars($fadeType, ENT_QUOTES, 'UTF-8'); ?>"
|
||||
<?php if ($slides) : ?>
|
||||
data-slide-content="<?php echo htmlspecialchars(json_encode($slides), ENT_QUOTES, 'UTF-8'); ?>"
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
>
|
||||
<?php // Background layer — solid colour, single image, slideshow, or video ?>
|
||||
@@ -55,11 +97,20 @@ $heightAttr = htmlspecialchars($heroHeight, ENT_QUOTES, 'UTF-8');
|
||||
<?php elseif ($heroMode === 'gradient') : ?>
|
||||
<div class="mokojoomhero__color" style="background: linear-gradient(<?php echo $gradientAngle; ?>deg, <?php echo htmlspecialchars($gradientStart, ENT_QUOTES, 'UTF-8'); ?>, <?php echo htmlspecialchars($gradientEnd, ENT_QUOTES, 'UTF-8'); ?>);"></div>
|
||||
<?php elseif ($heroMode === 'video' && $youtubeId) : ?>
|
||||
<?php if ($videoPoster) : ?>
|
||||
<div class="mokojoomhero__poster" style="background-image: url('<?php echo htmlspecialchars(\Joomla\CMS\Uri\Uri::root() . ltrim($videoPoster, '/'), ENT_QUOTES, 'UTF-8'); ?>');"></div>
|
||||
<?php endif; ?>
|
||||
<iframe class="mokojoomhero__video" src="https://www.youtube-nocookie.com/embed/<?php echo htmlspecialchars($youtubeId, ENT_QUOTES, 'UTF-8'); ?>?autoplay=1&mute=1&loop=1&playlist=<?php echo htmlspecialchars($youtubeId, ENT_QUOTES, 'UTF-8'); ?>&controls=0&showinfo=0&rel=0&modestbranding=1&playsinline=1&enablejsapi=1&origin=<?php echo htmlspecialchars(\Joomla\CMS\Uri\Uri::root(), ENT_QUOTES, 'UTF-8'); ?>" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||
<?php elseif ($heroMode === 'video' && $vimeoId) : ?>
|
||||
<?php if ($videoPoster) : ?>
|
||||
<div class="mokojoomhero__poster" style="background-image: url('<?php echo htmlspecialchars(\Joomla\CMS\Uri\Uri::root() . ltrim($videoPoster, '/'), ENT_QUOTES, 'UTF-8'); ?>');"></div>
|
||||
<?php endif; ?>
|
||||
<iframe class="mokojoomhero__video" src="https://player.vimeo.com/video/<?php echo htmlspecialchars($vimeoId, ENT_QUOTES, 'UTF-8'); ?>?autoplay=1&muted=1&loop=1&background=1" allow="autoplay" allowfullscreen></iframe>
|
||||
<?php elseif (($heroMode === 'video' || $heroMode === 'localvideo') && $videoUrl) : ?>
|
||||
<video class="mokojoomhero__video" autoplay muted loop playsinline>
|
||||
<?php if ($videoPoster) : ?>
|
||||
<div class="mokojoomhero__poster" style="background-image: url('<?php echo htmlspecialchars(\Joomla\CMS\Uri\Uri::root() . ltrim($videoPoster, '/'), ENT_QUOTES, 'UTF-8'); ?>');"></div>
|
||||
<?php endif; ?>
|
||||
<video class="mokojoomhero__video" autoplay muted loop playsinline<?php if ($videoPoster) : ?> poster="<?php echo htmlspecialchars(\Joomla\CMS\Uri\Uri::root() . ltrim($videoPoster, '/'), ENT_QUOTES, 'UTF-8'); ?>"<?php endif; ?>>
|
||||
<source src="<?php echo htmlspecialchars($videoUrl, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</video>
|
||||
<?php elseif ($heroImages) : ?>
|
||||
@@ -77,20 +128,32 @@ $heightAttr = htmlspecialchars($heroHeight, ENT_QUOTES, 'UTF-8');
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($showScrollIndicator) : ?>
|
||||
<button class="mokojoomhero__scroll-indicator" type="button" aria-label="Scroll down">
|
||||
<svg class="mokojoomhero__scroll-chevron" viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Overlay + content ?>
|
||||
<div class="mokojoomhero__overlay" style="background-color: <?php echo $rgba; ?>;">
|
||||
<div class="mokojoomhero__content" style="text-align: <?php echo htmlspecialchars($textAlign, ENT_QUOTES, 'UTF-8'); ?>; color: <?php echo htmlspecialchars($textColor, ENT_QUOTES, 'UTF-8'); ?>;">
|
||||
<?php if ($heroContent || $module->showtitle) : ?>
|
||||
<div class="mokojoomhero__overlay" style="<?php echo $overlayBg; ?> align-items: <?php echo $valignCss; ?>;">
|
||||
<div class="mokojoomhero__content<?php if ($contentAnimation !== 'none') : ?> mokojoomhero__content--anim-<?php echo htmlspecialchars($contentAnimation, ENT_QUOTES, 'UTF-8'); ?><?php endif; ?>" style="text-align: <?php echo htmlspecialchars($textAlign, ENT_QUOTES, 'UTF-8'); ?>; color: <?php echo htmlspecialchars($textColor, ENT_QUOTES, 'UTF-8'); ?>;<?php if ($contentAnimationDelay) : ?> animation-delay: <?php echo $contentAnimationDelay; ?>ms;<?php endif; ?>">
|
||||
<?php
|
||||
$displayTitle = ($contentSource === 'article' && $useArticleTitle && $articleTitle)
|
||||
? $articleTitle
|
||||
: $module->title;
|
||||
$showTitle = ($contentSource === 'article' && $useArticleTitle && $articleTitle) || $module->showtitle;
|
||||
?>
|
||||
<?php if ($heroContent || $showTitle) : ?>
|
||||
<?php if ($showCard) : ?>
|
||||
<div class="mokojoomhero__card"<?php if ($cardDelay) : ?> style="animation-delay: <?php echo $cardDelay; ?>ms;" data-card-delay="<?php echo $cardDelay; ?>"<?php endif; ?>>
|
||||
<?php if ($module->showtitle) : ?>
|
||||
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($module->title, ENT_QUOTES, 'UTF-8'); ?></h2>
|
||||
<?php if ($showTitle) : ?>
|
||||
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($displayTitle, ENT_QUOTES, 'UTF-8'); ?></h2>
|
||||
<?php endif; ?>
|
||||
<?php echo $heroContent; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php if ($module->showtitle) : ?>
|
||||
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($module->title, ENT_QUOTES, 'UTF-8'); ?></h2>
|
||||
<?php if ($showTitle) : ?>
|
||||
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($displayTitle, ENT_QUOTES, 'UTF-8'); ?></h2>
|
||||
<?php endif; ?>
|
||||
<?php echo $heroContent; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
PLG_SYSTEM_MOKOJOOMHERO="System - MokoJoomHero"
|
||||
PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero — license key validation"
|
||||
PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero"
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
PLG_SYSTEM_MOKOJOOMHERO="System - MokoJoomHero"
|
||||
PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero — license key validation"
|
||||
PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero"
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
-->
|
||||
<extension type="plugin" group="system" method="upgrade">
|
||||
<name>plg_system_mokojoomhero</name>
|
||||
<version>01.04.01-dev</version>
|
||||
<name>PLG_SYSTEM_MOKOJOOMHERO</name>
|
||||
<version>01.08.00-rc</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
@@ -25,10 +25,10 @@
|
||||
<folder>src</folder>
|
||||
</files>
|
||||
|
||||
<languages>
|
||||
<language tag="en-GB">language/en-GB/plg_system_mokojoomhero.ini</language>
|
||||
<language tag="en-GB">language/en-GB/plg_system_mokojoomhero.sys.ini</language>
|
||||
<language tag="en-US">language/en-US/plg_system_mokojoomhero.ini</language>
|
||||
<language tag="en-US">language/en-US/plg_system_mokojoomhero.sys.ini</language>
|
||||
<languages folder="language">
|
||||
<language tag="en-GB">en-GB/plg_system_mokojoomhero.ini</language>
|
||||
<language tag="en-GB">en-GB/plg_system_mokojoomhero.sys.ini</language>
|
||||
<language tag="en-US">en-US/plg_system_mokojoomhero.ini</language>
|
||||
<language tag="en-US">en-US/plg_system_mokojoomhero.sys.ini</language>
|
||||
</languages>
|
||||
</extension>
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Joomla\Plugin\System\MokoJoomHero\Extension;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Plugin\CMSPlugin;
|
||||
use Joomla\Event\SubscriberInterface;
|
||||
|
||||
@@ -21,70 +20,6 @@ class MokoJoomHero extends CMSPlugin implements SubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
'onAfterRoute' => 'onAfterRoute',
|
||||
];
|
||||
}
|
||||
|
||||
public function onAfterRoute(): void
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
|
||||
if ($app->isClient('administrator')) {
|
||||
$this->warnMissingLicenseKey();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn administrators once per session when no license key is configured.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function warnMissingLicenseKey(): void
|
||||
{
|
||||
$session = Factory::getSession();
|
||||
|
||||
if ($session->get('mokojoomhero.license_warned', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = Factory::getUser();
|
||||
|
||||
if ($user->guest || !$user->authorise('core.manage')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$session->set('mokojoomhero.license_warned', true);
|
||||
|
||||
try {
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName('extra_query'))
|
||||
->from($db->quoteName('#__update_sites'))
|
||||
->where($db->quoteName('name') . ' = ' . $db->quote('MokoJoomHero Updates'))
|
||||
->setLimit(1);
|
||||
$db->setQuery($query);
|
||||
$extraQuery = (string) $db->loadResult();
|
||||
|
||||
if (!empty($extraQuery)) {
|
||||
parse_str($extraQuery, $parsed);
|
||||
|
||||
if (!empty($parsed['dlid']) && preg_match('/^MOKO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/', $parsed['dlid'])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->getApplication()->enqueueMessage(
|
||||
'<strong>Moko Consulting License Key Required</strong> — '
|
||||
. 'No download key is configured. Updates will not be available until a valid license key is entered. '
|
||||
. 'Go to <a href="index.php?option=com_installer&view=updatesites">System → Update Sites</a> '
|
||||
. 'and enter your license key (<code>MOKO-XXXX-XXXX-XXXX-XXXX</code>) in the Download Key field '
|
||||
. 'for the MokoJoomHero update site.',
|
||||
'warning'
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
// Don't break admin over a license check
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
<extension type="package" method="upgrade">
|
||||
<name>Package - MokoJoomHero</name>
|
||||
<packagename>mokojoomhero</packagename>
|
||||
<version>01.04.01-dev</version>
|
||||
<version>01.08.00-rc</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<description>PKG_MOKOJOOMHERO_DESCRIPTION</description>
|
||||
<description>Random hero image slideshow or background video with content overlay. Includes the hero module and system plugin. By Moko Consulting.</description>
|
||||
|
||||
<scriptfile>pkg_script.php</scriptfile>
|
||||
|
||||
|
||||
+27
-11
@@ -16,7 +16,7 @@ use Joomla\CMS\Installer\InstallerAdapter;
|
||||
class Pkg_MokoJoomHeroInstallerScript
|
||||
{
|
||||
/**
|
||||
* Called after install/update.
|
||||
* Called after install/update — only enables the system plugin on fresh install.
|
||||
*
|
||||
* @param string $type Action type
|
||||
* @param InstallerAdapter $parent Installer adapter
|
||||
@@ -26,18 +26,34 @@ class Pkg_MokoJoomHeroInstallerScript
|
||||
public function postflight(string $type, InstallerAdapter $parent): void
|
||||
{
|
||||
if ($type === 'install') {
|
||||
$db = Factory::getDbo();
|
||||
try {
|
||||
$db = Factory::getDbo();
|
||||
|
||||
// Enable the system plugin automatically on fresh install
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__extensions'))
|
||||
->set($db->quoteName('enabled') . ' = 1')
|
||||
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
|
||||
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
|
||||
->where($db->quoteName('element') . ' = ' . $db->quote('mokojoomhero'));
|
||||
// Enable the system plugin automatically on fresh install
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__extensions'))
|
||||
->set($db->quoteName('enabled') . ' = 1')
|
||||
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
|
||||
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
|
||||
->where($db->quoteName('element') . ' = ' . $db->quote('mokojoomhero'));
|
||||
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
if ($db->getAffectedRows() === 0) {
|
||||
Factory::getApplication()->enqueueMessage(
|
||||
'MokoJoomHero: The system plugin could not be auto-enabled. '
|
||||
. 'Please enable it manually in Extensions → Plugins.',
|
||||
'warning'
|
||||
);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Factory::getApplication()->enqueueMessage(
|
||||
'MokoJoomHero: Failed to auto-enable system plugin: ' . $e->getMessage()
|
||||
. ' — Please enable it manually in Extensions → Plugins.',
|
||||
'warning'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
VERSION: 01.07.00
|
||||
VERSION: 01.08.00
|
||||
-->
|
||||
|
||||
<updates>
|
||||
|
||||
Reference in New Issue
Block a user