Implement PR-based changelog automation and sync roadmap with active development #66
18
.github/pull_request_template.md
vendored
18
.github/pull_request_template.md
vendored
@@ -4,6 +4,23 @@
|
||||
|
||||
## Change Summary
|
||||
|
||||
## Changelog Entry
|
||||
|
||||
> **Instructions:** Add your changelog entry below in Keep a Changelog format. This will be used to update CHANGELOG.md when the PR is merged.
|
||||
>
|
||||
> **Format:**
|
||||
> ```markdown
|
||||
> ### [Category]
|
||||
> - Brief description of change (#PR-number)
|
||||
> ```
|
||||
>
|
||||
> **Categories:** Added, Changed, Deprecated, Removed, Fixed, Security
|
||||
|
||||
```markdown
|
||||
### [Category]
|
||||
- Your changelog entry here
|
||||
```
|
||||
|
||||
## Testing Evidence
|
||||
|
||||
## Risk and Rollback
|
||||
@@ -14,6 +31,7 @@
|
||||
- [ ] Documentation updated if required
|
||||
- [ ] License header present where applicable
|
||||
- [ ] Linked issue(s) referenced
|
||||
- [ ] Changelog entry provided above
|
||||
|
||||
## Reviewer Notes
|
||||
|
||||
|
||||
194
.github/workflows/changelog-validation.yml
vendored
Normal file
194
.github/workflows/changelog-validation.yml
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
# 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
|
||||
|
||||
name: Changelog Validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize, reopened]
|
||||
branches:
|
||||
- main
|
||||
- 'dev/**'
|
||||
- 'rc/**'
|
||||
- 'version/**'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
validate-changelog-entry:
|
||||
name: Validate Changelog Entry
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check for changelog entry in PR description
|
||||
id: check_changelog
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prBody = context.payload.pull_request.body || '';
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
const prAuthor = context.payload.pull_request.user.login;
|
||||
|
||||
// Skip for automated PRs (e.g., Dependabot)
|
||||
const automatedAuthors = ['dependabot[bot]', 'github-actions[bot]'];
|
||||
if (automatedAuthors.includes(prAuthor)) {
|
||||
console.log('Skipping changelog check for automated PR');
|
||||
core.setOutput('has_entry', 'true');
|
||||
core.setOutput('skip', 'true');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if PR body contains changelog entry section
|
||||
const changelogSection = prBody.match(/## Changelog Entry[\s\S]*?```markdown([\s\S]*?)```/);
|
||||
|
||||
if (!changelogSection) {
|
||||
console.log('No changelog entry section found in PR template');
|
||||
core.setOutput('has_entry', 'false');
|
||||
core.setOutput('skip', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
const changelogContent = changelogSection[1].trim();
|
||||
|
||||
// Check if changelog entry is not just the template placeholder
|
||||
const isPlaceholder = changelogContent.includes('[Category]') ||
|
||||
changelogContent.includes('Your changelog entry here') ||
|
||||
changelogContent.length < 20;
|
||||
|
||||
if (isPlaceholder) {
|
||||
console.log('Changelog entry appears to be placeholder text');
|
||||
core.setOutput('has_entry', 'false');
|
||||
core.setOutput('skip', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that it contains a category
|
||||
const validCategories = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'];
|
||||
const hasValidCategory = validCategories.some(cat => changelogContent.includes(`### ${cat}`));
|
||||
|
||||
if (!hasValidCategory) {
|
||||
console.log('Changelog entry does not contain a valid category');
|
||||
core.setOutput('has_entry', 'false');
|
||||
core.setOutput('skip', 'false');
|
||||
core.setOutput('reason', 'missing_category');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Valid changelog entry found');
|
||||
core.setOutput('has_entry', 'true');
|
||||
core.setOutput('skip', 'false');
|
||||
core.setOutput('entry', changelogContent);
|
||||
|
||||
- name: Comment on PR if changelog entry is missing
|
||||
if: steps.check_changelog.outputs.has_entry == 'false' && steps.check_changelog.outputs.skip == 'false'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const reason = '${{ steps.check_changelog.outputs.reason }}';
|
||||
let message = '## ⚠️ Changelog Entry Required\n\n';
|
||||
|
||||
if (reason === 'missing_category') {
|
||||
message += 'Your PR includes a changelog entry, but it does not contain a valid category.\n\n';
|
||||
} else {
|
||||
message += 'This PR is missing a changelog entry or contains only placeholder text.\n\n';
|
||||
}
|
||||
|
||||
message += 'Please add a changelog entry in the "Changelog Entry" section of the PR description.\n\n';
|
||||
message += '### Valid Categories\n';
|
||||
message += '- **Added** - New features or files\n';
|
||||
message += '- **Changed** - Modifications to existing functionality\n';
|
||||
message += '- **Deprecated** - Features marked for future removal\n';
|
||||
message += '- **Removed** - Deleted features or files\n';
|
||||
message += '- **Fixed** - Bug fixes\n';
|
||||
message += '- **Security** - Security-related changes\n\n';
|
||||
message += '### Example\n';
|
||||
message += '```markdown\n';
|
||||
message += '### Added\n';
|
||||
message += '- New feature description (#' + context.payload.pull_request.number + ')\n\n';
|
||||
message += '### Changed\n';
|
||||
message += '- Modified behavior description (#' + context.payload.pull_request.number + ')\n';
|
||||
message += '```\n\n';
|
||||
message += 'See [CHANGELOG_PROCESS.md](https://github.com/mokoconsulting-tech/moko-cassiopeia/blob/main/docs/CHANGELOG_PROCESS.md) for detailed guidelines.';
|
||||
|
||||
// Check if we already commented
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number
|
||||
});
|
||||
|
||||
const botComment = comments.data.find(comment =>
|
||||
comment.user.login === 'github-actions[bot]' &&
|
||||
comment.body.includes('Changelog Entry Required')
|
||||
);
|
||||
|
||||
if (botComment) {
|
||||
// Update existing comment
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: botComment.id,
|
||||
body: message
|
||||
});
|
||||
} else {
|
||||
// Create new comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
body: message
|
||||
});
|
||||
}
|
||||
|
||||
- name: Add label if changelog is missing
|
||||
if: steps.check_changelog.outputs.has_entry == 'false' && steps.check_changelog.outputs.skip == 'false'
|
||||
uses: actions/github-script@v7
|
||||
continue-on-error: true
|
||||
with:
|
||||
script: |
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
labels: ['needs-changelog']
|
||||
});
|
||||
|
||||
- name: Remove label if changelog is present
|
||||
if: steps.check_changelog.outputs.has_entry == 'true' && steps.check_changelog.outputs.skip == 'false'
|
||||
uses: actions/github-script@v7
|
||||
continue-on-error: true
|
||||
with:
|
||||
script: |
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
name: 'needs-changelog'
|
||||
});
|
||||
} catch (error) {
|
||||
// Label might not exist, that's okay
|
||||
console.log('Label does not exist or already removed');
|
||||
}
|
||||
|
||||
- name: Set status
|
||||
if: steps.check_changelog.outputs.skip == 'false'
|
||||
run: |
|
||||
if [ "${{ steps.check_changelog.outputs.has_entry }}" == "true" ]; then
|
||||
echo "✅ Changelog entry found and validated"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Changelog entry is missing or invalid"
|
||||
echo "Please add a changelog entry to your PR description"
|
||||
exit 1
|
||||
fi
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -8,11 +8,31 @@
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia.Documentation
|
||||
PATH: ./CHANGELOG.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Changelog file documenting version history of Moko-Cassiopeia
|
||||
-->
|
||||
|
||||
# Changelog — Moko-Cassiopeia (VERSION: 03.05.00)
|
||||
# Changelog — Moko-Cassiopeia (VERSION: 03.06.00)
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- PR-based changelog process with comprehensive documentation (#66)
|
||||
- Created CHANGELOG_PROCESS.md guide with detailed workflow
|
||||
- Added changelog entry section to PR template
|
||||
- Integrated changelog guidance into CONTRIBUTING.md and WORKFLOW_GUIDE.md
|
||||
- GitHub Actions workflow for automatic changelog validation and PR labeling (#66)
|
||||
- Validates changelog entries in PR descriptions
|
||||
- Automatically comments with guidance on missing/invalid entries
|
||||
- Smart detection skips automated PRs
|
||||
|
||||
### Changed
|
||||
- Updated roadmap documentation based on current open pull requests (#66)
|
||||
- Added document generation system as planned feature (#66)
|
||||
- Synchronized roadmap version timeline with active development branches (#66)
|
||||
|
||||
## [03.06.00] 2026-01-28
|
||||
### Changed
|
||||
- Updated version to 03.06.00 across all files
|
||||
|
||||
## [03.05.01] 2026-01-09
|
||||
### Added
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia.Governance
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: CODE_OF_CONDUCT.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Contributor code of conduct for the Moko-Cassiopeia project.
|
||||
PATH: /CODE_OF_CONDUCT.md
|
||||
NOTE: This document defines behavioral expectations and enforcement processes.
|
||||
@@ -86,7 +86,7 @@ This project is managed from Tennessee, USA. This statement is informational and
|
||||
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
|
||||
* **Path:** /CODE_OF_CONDUCT.md
|
||||
* **Owner:** Moko Consulting
|
||||
* **Version:** 03.05.00
|
||||
* **Version:** 03.06.00
|
||||
* **Status:** Active
|
||||
* **Effective Date:** 2025-12-18
|
||||
* **Last Reviewed:** 2025-12-18
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia.Governance
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: CONTRIBUTING.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Contribution guidelines for the Moko-Cassiopeia project.
|
||||
PATH: /CONTRIBUTING.md
|
||||
NOTE: This document defines contribution workflow, standards, and governance alignment.
|
||||
@@ -61,6 +61,7 @@ The repository provides several tools to streamline development:
|
||||
2. Create a branch from the active development branch.
|
||||
3. Make focused, minimal changes that address a single concern.
|
||||
4. Submit a pull request with a clear description of intent and impact.
|
||||
5. **Include a changelog entry** in the PR template describing your changes (see [CHANGELOG_PROCESS.md](./docs/CHANGELOG_PROCESS.md)).
|
||||
|
||||
Direct commits to protected branches are not permitted.
|
||||
|
||||
@@ -88,6 +89,16 @@ Documentation changes must:
|
||||
* Avoid embedding version numbers in revision history tables.
|
||||
* Preserve existing structure unless a structural change is explicitly proposed.
|
||||
|
||||
## Changelog Maintenance
|
||||
|
||||
All changes must be documented in the changelog:
|
||||
|
||||
* **Include a changelog entry** in every pull request (see the PR template)
|
||||
* Follow [Keep a Changelog](https://keepachangelog.com/) format
|
||||
* Use appropriate categories: Added, Changed, Deprecated, Removed, Fixed, Security
|
||||
* Write from a user perspective, not implementation details
|
||||
* See [docs/CHANGELOG_PROCESS.md](./docs/CHANGELOG_PROCESS.md) for complete guidelines
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Commit messages should:
|
||||
@@ -133,7 +144,7 @@ Participation in this project is governed by the Code of Conduct. Unacceptable b
|
||||
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
|
||||
* **Path:** /CONTRIBUTING.md
|
||||
* **Owner:** Moko Consulting
|
||||
* **Version:** 03.05.00
|
||||
* **Version:** 03.06.00
|
||||
* **Status:** Active
|
||||
* **Effective Date:** 2025-12-18
|
||||
* **Last Reviewed:** 2025-12-18
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia.Governance
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: GOVERNANCE.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Project governance model, roles, and decision processes for Moko-Cassiopeia.
|
||||
PATH: /GOVERNANCE.md
|
||||
NOTE: This document defines authority, decision making, and escalation paths.
|
||||
@@ -103,7 +103,7 @@ This project is managed from Tennessee, USA. This statement is informational and
|
||||
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
|
||||
* **Path:** /GOVERNANCE.md
|
||||
* **Owner:** Moko Consulting
|
||||
* **Version:** 03.05.00
|
||||
* **Version:** 03.06.00
|
||||
* **Status:** Active
|
||||
* **Effective Date:** 2025-12-18
|
||||
* **Last Reviewed:** 2025-12-18
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
INGROUP: Moko-Cassiopeia.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: ./README.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Documentation for Moko-Cassiopeia template
|
||||
-->
|
||||
|
||||
# Moko-Cassiopeia (VERSION: 03.05.00)
|
||||
# Moko-Cassiopeia (VERSION: 03.06.00)
|
||||
|
||||
A modern, lightweight enhancement layer for Joomla's Cassiopeia
|
||||
template.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia.Governance
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: SECURITY.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Security policy and vulnerability reporting process for Moko-Cassiopeia.
|
||||
PATH: /SECURITY.md
|
||||
NOTE: This policy is process oriented and does not replace secure engineering practices.
|
||||
@@ -153,7 +153,7 @@ If you want credit, include the name or handle to list in an advisory. If you pr
|
||||
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
|
||||
* **Path:** /SECURITY.md
|
||||
* **Owner:** Moko Consulting
|
||||
* **Version:** 03.05.00
|
||||
* **Version:** 03.06.00
|
||||
* **Status:** Active
|
||||
* **Effective Date:** 2025-12-18
|
||||
* **Last Reviewed:** 2025-12-18
|
||||
|
||||
424
docs/CHANGELOG_PROCESS.md
Normal file
424
docs/CHANGELOG_PROCESS.md
Normal file
@@ -0,0 +1,424 @@
|
||||
<!--
|
||||
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
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: docs/CHANGELOG_PROCESS.md
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Process guide for maintaining changelog based on pull requests
|
||||
PATH: /docs/CHANGELOG_PROCESS.md
|
||||
-->
|
||||
|
||||
# Changelog Process Guide
|
||||
|
||||
This guide explains how to maintain the changelog based on pull requests, ensuring that all changes are properly documented.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Changelog Format](#changelog-format)
|
||||
- [PR-Based Changelog Workflow](#pr-based-changelog-workflow)
|
||||
- [Writing Good Changelog Entries](#writing-good-changelog-entries)
|
||||
- [Categories Explained](#categories-explained)
|
||||
- [Examples](#examples)
|
||||
- [Automation](#automation)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Quick Reference](#quick-reference)
|
||||
- [Resources](#resources)
|
||||
- [Related Documentation](#related-documentation)
|
||||
|
||||
## Overview
|
||||
|
||||
The Moko-Cassiopeia project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format for maintaining the CHANGELOG.md file. This ensures that changes are:
|
||||
|
||||
- **Human-readable** - Users can quickly understand what changed
|
||||
- **Grouped by category** - Changes are organized by type (Added, Changed, etc.)
|
||||
- **Version-based** - Changes are associated with specific releases
|
||||
- **PR-linked** - Each entry references the pull request that introduced it
|
||||
|
||||
## Changelog Format
|
||||
|
||||
The changelog follows this structure:
|
||||
|
||||
```markdown
|
||||
# Changelog — Moko-Cassiopeia (VERSION: X.Y.Z)
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- New feature description (#123)
|
||||
|
||||
### Changed
|
||||
- Modified functionality description (#124)
|
||||
|
||||
### Fixed
|
||||
- Bug fix description (#125)
|
||||
|
||||
## [X.Y.Z] YYYY-MM-DD
|
||||
### Added
|
||||
- Released feature description (#120)
|
||||
|
||||
### Changed
|
||||
- Released modification description (#121)
|
||||
```
|
||||
|
||||
## PR-Based Changelog Workflow
|
||||
|
||||
### For Contributors
|
||||
|
||||
When creating a pull request:
|
||||
|
||||
1. **Fill out the PR template** - Include all required sections
|
||||
2. **Add a Changelog Entry** - In the "Changelog Entry" section of the PR template, provide:
|
||||
```markdown
|
||||
### Added
|
||||
- New feature that does X (#PR-number)
|
||||
```
|
||||
3. **Use the correct category** - Choose from: Added, Changed, Deprecated, Removed, Fixed, Security
|
||||
4. **Be descriptive** - Explain what changed from a user's perspective
|
||||
5. **Check the changelog checkbox** - Confirm you've provided an entry
|
||||
|
||||
### For Maintainers
|
||||
|
||||
When merging a pull request:
|
||||
|
||||
1. **Review the changelog entry** - Ensure it's clear and accurate
|
||||
2. **Copy to CHANGELOG.md** - Add the entry to the `[Unreleased]` section
|
||||
3. **Add PR number** - Include the PR number in parentheses: `(#123)`
|
||||
4. **Maintain category order** - Keep categories in standard order
|
||||
5. **Update version on release** - Move `[Unreleased]` entries to versioned section
|
||||
|
||||
### Release Process
|
||||
|
||||
When creating a new release:
|
||||
|
||||
1. **Move unreleased entries** - Transfer from `[Unreleased]` to `[X.Y.Z] YYYY-MM-DD`
|
||||
2. **Update version header** - Change the top-level version number
|
||||
3. **Add release date** - Use format: `[X.Y.Z] YYYY-MM-DD`
|
||||
4. **Clear unreleased section** - Leave `[Unreleased]` empty or remove it
|
||||
5. **Commit changelog** - Include in the release commit
|
||||
|
||||
## Writing Good Changelog Entries
|
||||
|
||||
### DO ✅
|
||||
|
||||
- **Use imperative mood** - "Add feature" not "Added feature"
|
||||
- **Be specific** - Mention what component/file changed
|
||||
- **Focus on user impact** - What does this mean for users?
|
||||
- **Include PR reference** - Always add `(#123)`
|
||||
- **Keep it concise** - One line per change when possible
|
||||
|
||||
**Good examples:**
|
||||
```markdown
|
||||
### Added
|
||||
- Installation script for automated media folder cleanup during updates (#65)
|
||||
- Document generation system as planned feature (#66)
|
||||
|
||||
### Changed
|
||||
- Asset minification now linked to Joomla's global cache system (#62)
|
||||
- Updated version to 03.08.00 across 24+ files (#65)
|
||||
|
||||
### Fixed
|
||||
- Corrected stylesheet inconsistencies between Bootstrap 5 helpers and template overrides (#42)
|
||||
```
|
||||
|
||||
### DON'T ❌
|
||||
|
||||
- **Be vague** - "Fixed bug" or "Updated file"
|
||||
- **Use past tense** - "Added feature" should be "Add feature"
|
||||
- **Skip the PR number** - Always include it
|
||||
- **Duplicate entries** - Combine related changes
|
||||
- **Include implementation details** - Focus on user-facing changes
|
||||
|
||||
**Bad examples:**
|
||||
```markdown
|
||||
### Changed
|
||||
- Updated some files (no PR reference)
|
||||
- Fixed it (too vague)
|
||||
- Modified AssetMinifier.php parameter logic (implementation detail)
|
||||
```
|
||||
|
||||
## Categories Explained
|
||||
|
||||
### Added
|
||||
New features, files, or capabilities added to the template.
|
||||
|
||||
**Examples:**
|
||||
- New template parameters
|
||||
- New layout options
|
||||
- New helper classes
|
||||
- New documentation files
|
||||
- New configuration options
|
||||
|
||||
### Changed
|
||||
Modifications to existing functionality that change behavior.
|
||||
|
||||
**Examples:**
|
||||
- Updated dependencies
|
||||
- Modified default settings
|
||||
- Changed CSS styles
|
||||
- Refactored code (when it affects behavior)
|
||||
- Updated documentation
|
||||
|
||||
### Deprecated
|
||||
Features that will be removed in future versions but still work.
|
||||
|
||||
**Examples:**
|
||||
- Template parameters marked for removal
|
||||
- Old API methods still supported
|
||||
- Legacy configuration options
|
||||
|
||||
### Removed
|
||||
Features, files, or capabilities that have been deleted.
|
||||
|
||||
**Examples:**
|
||||
- Removed deprecated parameters
|
||||
- Deleted unused files
|
||||
- Removed old workarounds
|
||||
- Deleted legacy code
|
||||
|
||||
### Fixed
|
||||
Bug fixes and corrections.
|
||||
|
||||
**Examples:**
|
||||
- Fixed CSS rendering issues
|
||||
- Corrected PHP errors
|
||||
- Fixed broken links
|
||||
- Resolved accessibility issues
|
||||
- Patched security vulnerabilities (use Security for serious ones)
|
||||
|
||||
### Security
|
||||
Security-related changes and vulnerability fixes.
|
||||
|
||||
**Examples:**
|
||||
- Patched XSS vulnerabilities
|
||||
- Updated vulnerable dependencies
|
||||
- Fixed security misconfigurations
|
||||
- Added security hardening
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Feature Addition PR
|
||||
|
||||
**PR #65: Add Installation Script**
|
||||
|
||||
In the PR template:
|
||||
```markdown
|
||||
### Changelog Entry
|
||||
|
||||
### Added
|
||||
- Installation script for automated media folder cleanup during template updates (#65)
|
||||
- Implements InstallerScriptInterface with lifecycle hooks
|
||||
- Recursive cleanup of empty directories
|
||||
- Operation logging to logs/moko_cassiopeia_cleanup.php
|
||||
|
||||
### Changed
|
||||
- Updated version to 03.08.00 across 24+ files (#65)
|
||||
```
|
||||
|
||||
In CHANGELOG.md (after merge):
|
||||
```markdown
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Installation script for automated media folder cleanup during template updates (#65)
|
||||
- Implements InstallerScriptInterface with lifecycle hooks
|
||||
- Recursive cleanup of empty directories
|
||||
- Operation logging to logs/moko_cassiopeia_cleanup.php
|
||||
|
||||
### Changed
|
||||
- Updated version to 03.08.00 across 24+ files (#65)
|
||||
```
|
||||
|
||||
### Example 2: Bug Fix PR
|
||||
|
||||
**PR #123: Fix Dark Mode Toggle**
|
||||
|
||||
In the PR template:
|
||||
```markdown
|
||||
### Changelog Entry
|
||||
|
||||
### Fixed
|
||||
- Dark mode toggle not persisting user preference in localStorage (#123)
|
||||
- Toggle switch visual state not syncing with system theme preference (#123)
|
||||
```
|
||||
|
||||
### Example 3: Multiple Changes PR
|
||||
|
||||
**PR #62: Cache Integration**
|
||||
|
||||
In the PR template:
|
||||
```markdown
|
||||
### Changelog Entry
|
||||
|
||||
### Changed
|
||||
- Asset minification now linked to Joomla's global cache system (#62)
|
||||
- Cache enabled: minified assets (`.min` suffix) created and used
|
||||
- Cache disabled: non-minified assets used, minified files deleted
|
||||
|
||||
### Deprecated
|
||||
- Template-specific `developmentmode` parameter (replaced by Joomla cache setting) (#62)
|
||||
```
|
||||
|
||||
## Automation
|
||||
|
||||
### Current Automation
|
||||
|
||||
The repository now includes automated changelog validation:
|
||||
|
||||
- ✅ **GitHub Actions workflow** validates changelog entries in PRs
|
||||
- ✅ **Automatic PR labeling** based on changelog status
|
||||
- ✅ **PR comments** with guidance for missing/invalid entries
|
||||
- ✅ **Smart detection** skips automated PRs (Dependabot, bots)
|
||||
|
||||
**Workflow:** `.github/workflows/changelog-validation.yml`
|
||||
|
||||
The workflow:
|
||||
1. Checks PR description for changelog entry
|
||||
2. Validates entry format and category
|
||||
3. Comments on PR if entry is missing or invalid
|
||||
4. Adds/removes "needs-changelog" label
|
||||
5. Fails check if changelog is missing (except for automated PRs)
|
||||
|
||||
### Future Automation (Planned)
|
||||
|
||||
Future enhancements may include:
|
||||
|
||||
- **Semi-automated CHANGELOG.md updates** on PR merge
|
||||
- **Release notes generation** from changelog entries
|
||||
- **Changelog preview** in PR comments showing how entry will appear
|
||||
- **Multi-format export** for release notes
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For All Contributors
|
||||
|
||||
1. ✅ **Always provide a changelog entry** - Every PR should document its changes
|
||||
2. ✅ **Review existing entries** - Check for similar changes to maintain consistency
|
||||
3. ✅ **Test your entry format** - Ensure markdown renders correctly
|
||||
4. ✅ **Link the PR** - Always include `(#PR-number)` at the end
|
||||
5. ✅ **Think user-first** - Write from the perspective of someone using the template
|
||||
|
||||
### For Maintainers
|
||||
|
||||
1. ✅ **Review every changelog entry** - Don't merge PRs with poor/missing entries
|
||||
2. ✅ **Keep categories in order** - Added, Changed, Deprecated, Removed, Fixed, Security
|
||||
3. ✅ **Merge related entries** - Combine multiple PRs for the same feature
|
||||
4. ✅ **Update promptly** - Add entries to CHANGELOG.md as PRs are merged
|
||||
5. ✅ **Version regularly** - Move unreleased entries to version sections on release
|
||||
|
||||
### Version Management
|
||||
|
||||
1. ✅ **Use semantic versioning** - Major.Minor.Patch (03.06.00)
|
||||
2. ✅ **Update version header** - Keep VERSION comment in sync
|
||||
3. ✅ **Date releases** - Use YYYY-MM-DD format
|
||||
4. ✅ **Link releases** - Add GitHub release links at bottom of changelog
|
||||
5. ✅ **Keep history** - Never delete old version entries
|
||||
|
||||
### Quality Control
|
||||
|
||||
1. ✅ **Consistent language** - Maintain similar writing style across entries
|
||||
2. ✅ **No duplicates** - Check for existing entries before adding
|
||||
3. ✅ **Proper grammar** - Proofread entries before committing
|
||||
4. ✅ **Clear categorization** - Ensure changes are in the right category
|
||||
5. ✅ **Complete information** - Include all necessary context
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Missing Changelog Entry
|
||||
|
||||
**Problem:** PR merged without changelog entry
|
||||
|
||||
**Solution:**
|
||||
1. Create a follow-up commit to CHANGELOG.md
|
||||
2. Add the missing entry with PR reference
|
||||
3. Consider making changelog entry mandatory in PR checks
|
||||
|
||||
### Wrong Category
|
||||
|
||||
**Problem:** Entry is in the wrong category
|
||||
|
||||
**Solution:**
|
||||
1. Move entry to correct category
|
||||
2. Update PR template guidance if confusion is common
|
||||
3. Provide examples in code review
|
||||
|
||||
### Duplicate Entries
|
||||
|
||||
**Problem:** Same change documented multiple times
|
||||
|
||||
**Solution:**
|
||||
1. Consolidate entries into one comprehensive entry
|
||||
2. Keep all PR references: `(#123, #124, #125)`
|
||||
3. Ensure the combined entry captures all aspects
|
||||
|
||||
### Unclear Description
|
||||
|
||||
**Problem:** Changelog entry is too vague or technical
|
||||
|
||||
**Solution:**
|
||||
1. Rewrite from user perspective
|
||||
2. Ask the PR author for clarification
|
||||
3. Add more context about the impact
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Changelog Entry Template
|
||||
|
||||
```markdown
|
||||
### [Category]
|
||||
- [Brief description of what changed from user perspective] (#PR-number)
|
||||
- [Optional: Additional detail]
|
||||
- [Optional: Additional detail]
|
||||
```
|
||||
|
||||
### Common Phrases
|
||||
|
||||
- "Add [feature] to [component]"
|
||||
- "Update [component] to [new behavior]"
|
||||
- "Fix [issue] in [component]"
|
||||
- "Remove [feature] from [component]"
|
||||
- "Deprecate [feature] in favor of [replacement]"
|
||||
- "Improve [component] performance/accessibility/security"
|
||||
|
||||
### Checklist
|
||||
|
||||
Before submitting PR:
|
||||
- [ ] Changelog entry provided in PR template
|
||||
- [ ] Entry uses correct category
|
||||
- [ ] Entry is user-focused, not implementation-focused
|
||||
- [ ] Entry includes PR number
|
||||
- [ ] Entry uses imperative mood
|
||||
- [ ] Entry is clear and concise
|
||||
|
||||
Before merging PR:
|
||||
- [ ] Changelog entry is accurate
|
||||
- [ ] Changelog entry is well-written
|
||||
- [ ] Category is appropriate
|
||||
- [ ] PR number is correct
|
||||
- [ ] Entry will be copied to CHANGELOG.md
|
||||
|
||||
## Resources
|
||||
|
||||
- [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Official format guide
|
||||
- [Semantic Versioning](https://semver.org/) - Version numbering standard
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/) - Commit message format
|
||||
- [GitHub Flow](https://guides.github.com/introduction/flow/) - Branch and PR workflow
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [WORKFLOW_GUIDE.md](./WORKFLOW_GUIDE.md) - GitHub Actions and development workflows
|
||||
- [CONTRIBUTING.md](../CONTRIBUTING.md) - General contribution guidelines
|
||||
- [README.md](../README.md) - Project overview
|
||||
- [ROADMAP.md](./ROADMAP.md) - Feature planning and version timeline
|
||||
|
||||
---
|
||||
|
||||
**Document Version:** 1.0.0
|
||||
**Last Updated:** 2026-01-28
|
||||
**Maintained by:** Moko Consulting Engineering
|
||||
@@ -271,7 +271,7 @@ make test
|
||||
|
||||
### Version Management
|
||||
|
||||
- Use semantic versioning: Major.Minor.Patch (03.05.00)
|
||||
- Use semantic versioning: Major.Minor.Patch (03.06.00)
|
||||
- Update CHANGELOG.md with all changes
|
||||
- Follow the version hierarchy: dev → rc → version → main
|
||||
- Never skip stages in the release process
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: docs/README.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Documentation index for Moko-Cassiopeia template
|
||||
PATH: /docs/README.md
|
||||
-->
|
||||
@@ -34,6 +34,12 @@ This directory contains comprehensive documentation for the Moko-Cassiopeia Joom
|
||||
* Release process
|
||||
* Pull request guidelines
|
||||
|
||||
* **[Changelog Process Guide](CHANGELOG_PROCESS.md)** - Maintaining the changelog
|
||||
* PR-based changelog workflow
|
||||
* Writing good changelog entries
|
||||
* Categories and formatting
|
||||
* Automation and best practices
|
||||
|
||||
* **[Joomla Development Guide](JOOMLA_DEVELOPMENT.md)** - Joomla-specific development
|
||||
* Testing with Codeception
|
||||
* PHP quality checks (PHPStan, PHPCS)
|
||||
@@ -41,7 +47,7 @@ This directory contains comprehensive documentation for the Moko-Cassiopeia Joom
|
||||
* Multi-version testing
|
||||
|
||||
* **[Roadmap](ROADMAP.md)** - Version-specific roadmap
|
||||
* Current features (v03.05.00)
|
||||
* Current features (v03.06.00)
|
||||
* Feature evolution timeline
|
||||
* Planned enhancements
|
||||
* Development priorities
|
||||
@@ -58,6 +64,7 @@ moko-cassiopeia/
|
||||
│ ├── README.md # This file - documentation index
|
||||
│ ├── QUICK_START.md # Quick start guide for developers
|
||||
│ ├── WORKFLOW_GUIDE.md # Development workflow guide
|
||||
│ ├── CHANGELOG_PROCESS.md # Changelog maintenance guide
|
||||
│ ├── JOOMLA_DEVELOPMENT.md # Joomla-specific development guide
|
||||
│ └── ROADMAP.md # Version-specific roadmap
|
||||
├── src/ # Template source code
|
||||
@@ -105,7 +112,7 @@ This project adheres to [MokoStandards](https://github.com/mokoconsulting-tech/M
|
||||
* Repository: [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
|
||||
* Path: /docs/README.md
|
||||
* Owner: Moko Consulting
|
||||
* Version: 03.05.00
|
||||
* Version: 03.06.00
|
||||
* Status: Active
|
||||
* Effective Date: 2026-01-09
|
||||
|
||||
@@ -113,5 +120,6 @@ This project adheres to [MokoStandards](https://github.com/mokoconsulting-tech/M
|
||||
|
||||
| Date | Change Summary | Author |
|
||||
| ---------- | ----------------------------------------------------- | --------------- |
|
||||
| 2026-01-09 | Initial documentation index created for MokoStandards compliance. | GitHub Copilot |
|
||||
| 2026-01-28 | Added CHANGELOG_PROCESS.md reference and link. | GitHub Copilot |
|
||||
| 2026-01-27 | Updated with roadmap link and version to 03.05.01. | GitHub Copilot |
|
||||
| 2026-01-09 | Initial documentation index created for MokoStandards compliance. | GitHub Copilot |
|
||||
|
||||
100
docs/ROADMAP.md
100
docs/ROADMAP.md
@@ -10,12 +10,12 @@
|
||||
INGROUP: Moko-Cassiopeia.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
FILE: docs/ROADMAP.md
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Version-specific roadmap for Moko-Cassiopeia template
|
||||
PATH: /docs/ROADMAP.md
|
||||
-->
|
||||
|
||||
# Moko-Cassiopeia Roadmap (VERSION: 03.05.00)
|
||||
# Moko-Cassiopeia Roadmap (VERSION: 03.06.00)
|
||||
|
||||
This document provides a comprehensive, version-specific roadmap for the Moko-Cassiopeia Joomla template, tracking feature evolution, current capabilities, and planned enhancements.
|
||||
|
||||
@@ -24,7 +24,7 @@ This document provides a comprehensive, version-specific roadmap for the Moko-Ca
|
||||
- [Version Timeline](#version-timeline)
|
||||
- [Past Releases](#past-releases)
|
||||
- [Future Roadmap (5-Year Plan)](#future-roadmap-5-year-plan)
|
||||
- [Current Release (v03.05.00)](#current-release-v030500)
|
||||
- [Current Release (v03.06.00)](#current-release-v030600)
|
||||
- [Implemented Features](#implemented-features)
|
||||
- [Planned Features](#planned-features)
|
||||
- [Development Priorities](#development-priorities)
|
||||
@@ -51,8 +51,42 @@ This document provides a comprehensive, version-specific roadmap for the Moko-Ca
|
||||
- Enforced repository compliance with MokoStandards
|
||||
- Improved security posture with automated scanning
|
||||
|
||||
### v03.07.00 (2026-01-28) - Roadmap Update
|
||||
**Status**: In Development (Open PR #66)
|
||||
|
||||
**Changed**:
|
||||
- Updated roadmap documentation based on current open pull requests
|
||||
- Added document generation system as planned feature
|
||||
- Synchronized roadmap version timeline with active development branches
|
||||
- Enhanced future roadmap planning with documentation capabilities
|
||||
|
||||
### v03.08.00 (2026-01-28) - Installation Automation & Cache Integration
|
||||
**Status**: In Development (Open PR #65, #62)
|
||||
|
||||
**Added**:
|
||||
- Installation script (`src/templates/script.php`) for automated media folder cleanup during template updates (PR #65)
|
||||
- Implements `InstallerScriptInterface` with lifecycle hooks
|
||||
- Automatic removal of deprecated files/folders during updates
|
||||
- Recursive cleanup of empty directories
|
||||
- Operation logging to `logs/moko_cassiopeia_cleanup.php`
|
||||
- Validates Joomla 4.0+ and PHP 7.4+ requirements
|
||||
|
||||
**Changed**:
|
||||
- Asset minification now linked to Joomla's global cache system (PR #62)
|
||||
- When cache enabled: minified assets (`.min` suffix) are created and used
|
||||
- When cache disabled: non-minified assets used, minified files deleted
|
||||
- Replaced template-specific `developmentmode` parameter with Joomla cache configuration
|
||||
- `AssetMinifier.php` updated with inverted parameter logic for cache semantics
|
||||
- Updated version to 03.08.00 across 24+ files (CSS/JS, PHP/Config, templateDetails.xml, joomla.asset.json) (PR #65)
|
||||
|
||||
### v03.06.00 (2026-01-28) - Version Update
|
||||
**Status**: Released
|
||||
|
||||
**Changed**:
|
||||
- Updated version to 03.06.00 across all files
|
||||
|
||||
### v03.05.00 (2026-01-04) - Workflow & Governance
|
||||
**Status**: Current Release (in code)
|
||||
**Status**: Mentioned in CHANGELOG (v03.05.00)
|
||||
|
||||
**Added**:
|
||||
- `.github/workflows` directory structure
|
||||
@@ -163,7 +197,8 @@ The following versions represent our planned annual major releases, each buildin
|
||||
- Live reload during development
|
||||
- Enhanced error logging and diagnostics
|
||||
- Template debugging tools
|
||||
- Style guide generator
|
||||
- Document generation system (style guides, API docs, parameter reference)
|
||||
- Automated documentation from code annotations
|
||||
|
||||
- **Content Display Features**
|
||||
- Soft offline mode (category-based access during maintenance)
|
||||
@@ -294,7 +329,7 @@ The following versions represent our planned annual major releases, each buildin
|
||||
- Template backup/restore functionality
|
||||
- Template A/B testing support
|
||||
- Multi-language template variations
|
||||
- Template documentation generator
|
||||
- Enhanced document generation (multi-format export, interactive docs)
|
||||
|
||||
---
|
||||
|
||||
@@ -355,7 +390,7 @@ The following versions represent our planned annual major releases, each buildin
|
||||
**Template Infrastructure**:
|
||||
- Template pattern library
|
||||
- Design token system
|
||||
- Template component documentation
|
||||
- Advanced document generation with live previews
|
||||
- Automated template testing suite
|
||||
- Template performance monitoring
|
||||
|
||||
@@ -431,7 +466,9 @@ The following versions represent our planned annual major releases, each buildin
|
||||
|
||||
---
|
||||
|
||||
## Current Release (v03.05.00)
|
||||
## Current Release (v03.06.00)
|
||||
|
||||
**Note**: v03.07.00 (PR #66), v03.08.00 (PR #65, #62) are currently in development.
|
||||
|
||||
### System Requirements
|
||||
- **Joomla**: 4.4.x or 5.x
|
||||
@@ -542,8 +579,11 @@ The following versions represent our planned annual major releases, each buildin
|
||||
|
||||
#### Asset Management
|
||||
- **Joomla WAM**: Complete asset registry in `joomla.asset.json`
|
||||
- **Development/Production Modes**: Minified and unminified assets
|
||||
- **Cache-Based Minification**: Asset minification controlled by Joomla cache system
|
||||
- Cache enabled: Minified assets (`.min` suffix) created and used
|
||||
- Cache disabled: Non-minified assets used, minified files automatically removed
|
||||
- **Dependency Management**: Automatic script/style loading
|
||||
- **Installation Script**: Automated cleanup of deprecated files during updates
|
||||
|
||||
### 🏗️ Template Overrides
|
||||
|
||||
@@ -671,6 +711,23 @@ The following versions represent our planned annual major releases, each buildin
|
||||
**Description**: Separate TODO tracking file
|
||||
**Purpose**: Centralized issue and feature tracking outside changelog
|
||||
|
||||
#### Document Generation System
|
||||
**Status**: Planned
|
||||
**Description**: Automated documentation generation from template code and configuration
|
||||
**Potential Features**:
|
||||
- Template documentation generator from inline code comments
|
||||
- Automatic parameter reference documentation
|
||||
- Style guide generation from CSS/SCSS files
|
||||
- Module position documentation with visual layout diagrams
|
||||
- Template override documentation
|
||||
- Configuration guide generation
|
||||
- API documentation for template helper classes
|
||||
**Use Cases**:
|
||||
- Maintain up-to-date documentation automatically
|
||||
- Generate user-friendly configuration guides
|
||||
- Create developer reference documentation
|
||||
- Export documentation in multiple formats (HTML, PDF, Markdown)
|
||||
|
||||
### 🔮 Future Enhancements
|
||||
|
||||
#### Development Mode (Commented Out)
|
||||
@@ -709,11 +766,15 @@ The following versions represent our planned annual major releases, each buildin
|
||||
## Development Priorities
|
||||
|
||||
### Immediate Focus (v03.x - 2026)
|
||||
1. **TODO Tracking System**: Implement separate file for issue tracking
|
||||
2. **Soft Offline Mode**: Complete category-based offline access
|
||||
3. **Security Updates**: Maintain Dependabot and CodeQL scans
|
||||
4. **Documentation**: Keep docs synchronized with features
|
||||
5. **Bug Fixes**: Address reported issues and edge cases
|
||||
1. **Roadmap Documentation** (v03.07.00): Update roadmap with current development status (PR #66)
|
||||
2. **Installation Automation** (v03.08.00): Complete installation script for automated cleanup (PR #65)
|
||||
3. **Cache-Based Asset Minification** (v03.08.00): Finalize integration with Joomla cache system (PR #62)
|
||||
4. **Document Generation System**: Implement automated documentation generation
|
||||
5. **TODO Tracking System**: Implement separate file for issue tracking
|
||||
6. **Soft Offline Mode**: Complete category-based offline access
|
||||
7. **Security Updates**: Maintain Dependabot and CodeQL scans
|
||||
8. **Documentation**: Keep docs synchronized with features
|
||||
9. **Bug Fixes**: Address reported issues and edge cases
|
||||
|
||||
### v04.00.00 Priorities (2027) - Template Foundation
|
||||
1. **WCAG 2.1 AA Compliance**: Full template accessibility audit and implementation
|
||||
@@ -835,15 +896,18 @@ Have ideas for future features? We welcome community input!
|
||||
* Repository: [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
|
||||
* Path: /docs/ROADMAP.md
|
||||
* Owner: Moko Consulting
|
||||
* Version: 03.05.00
|
||||
* Version: 03.06.00
|
||||
* Status: Active
|
||||
* Last Updated: 2026-01-27
|
||||
* Last Updated: 2026-01-28
|
||||
* Classification: Public Open Source Documentation
|
||||
|
||||
## Revision History
|
||||
|
||||
| Date | Change Summary | Author |
|
||||
| ---------- | ----------------------------------------------------- | --------------- |
|
||||
| 2026-01-27 | Initial version-specific roadmap generated from codebase scan. | GitHub Copilot |
|
||||
| 2026-01-27 | Added 5-year future roadmap with annual major version releases (v04-v08). | GitHub Copilot |
|
||||
| 2026-01-28 | Clarified version numbers: PR #66 (v03.07.00), PR #65 (v03.08.00). | GitHub Copilot |
|
||||
| 2026-01-28 | Added document generation system as planned feature. | GitHub Copilot |
|
||||
| 2026-01-28 | Updated roadmap based on open PRs #62, #65, and #66. | GitHub Copilot |
|
||||
| 2026-01-27 | Refocused roadmap to concentrate on template-oriented features only. | GitHub Copilot |
|
||||
| 2026-01-27 | Added 5-year future roadmap with annual major version releases (v04-v08). | GitHub Copilot |
|
||||
| 2026-01-27 | Initial version-specific roadmap generated from codebase scan. | GitHub Copilot |
|
||||
|
||||
@@ -134,7 +134,7 @@ codecept run
|
||||
**How to run:**
|
||||
1. Go to Actions → Create version branch
|
||||
2. Click "Run workflow"
|
||||
3. Enter version (e.g., 03.05.00)
|
||||
3. Enter version (e.g., 03.06.00)
|
||||
4. Select branch prefix (dev/, rc/, or version/)
|
||||
5. Click "Run workflow"
|
||||
|
||||
@@ -283,7 +283,30 @@ unzip -l dist/moko-cassiopeia-*.zip
|
||||
|
||||
### Updating CHANGELOG
|
||||
|
||||
Update CHANGELOG.md manually or via pull request following the existing format.
|
||||
The changelog is maintained based on pull requests. Every PR should include a changelog entry.
|
||||
|
||||
**Process:**
|
||||
1. When creating a PR, fill out the "Changelog Entry" section in the PR template
|
||||
2. Follow the Keep a Changelog format (Added, Changed, Fixed, etc.)
|
||||
3. Maintainers will copy the entry to CHANGELOG.md upon merge
|
||||
4. See [CHANGELOG_PROCESS.md](./CHANGELOG_PROCESS.md) for detailed guidelines
|
||||
|
||||
**Example changelog entry in PR:**
|
||||
```markdown
|
||||
### Added
|
||||
- Installation script for automated media folder cleanup (#65)
|
||||
|
||||
### Changed
|
||||
- Asset minification linked to Joomla cache system (#62)
|
||||
```
|
||||
|
||||
**Quick reference:**
|
||||
- **Added** - New features or files
|
||||
- **Changed** - Modifications to existing functionality
|
||||
- **Deprecated** - Features marked for future removal
|
||||
- **Removed** - Deleted features or files
|
||||
- **Fixed** - Bug fixes
|
||||
- **Security** - Security-related changes
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -322,7 +345,7 @@ make validate-required
|
||||
git branch -r | grep dev/
|
||||
|
||||
# Delete remote branch if needed (carefully!)
|
||||
git push origin --delete dev/03.05.00
|
||||
git push origin --delete dev/03.06.00
|
||||
```
|
||||
|
||||
#### "Missing required secrets"
|
||||
@@ -381,7 +404,7 @@ phpcs --standard=phpcs.xml --report=source src/
|
||||
1. **Always use version branches:** dev/X.Y.Z, rc/X.Y.Z, version/X.Y.Z
|
||||
2. **Follow hierarchy:** dev → rc → version → main
|
||||
3. **Update CHANGELOG:** Document all changes in Unreleased section
|
||||
4. **Semantic versioning:** Major.Minor.Patch (03.05.00)
|
||||
4. **Semantic versioning:** Major.Minor.Patch (03.06.00)
|
||||
|
||||
### Code Quality
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; ; Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||
;
|
||||
; This file is part of a Moko Consulting project.
|
||||
;
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
--dark-border-subtle: #2b323b;
|
||||
|
||||
/* Typography & layout */
|
||||
--body-font-family: var(--optain-cassiopeia-font-family-body, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
|
||||
--body-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
--body-font-size: 1rem;
|
||||
--body-font-weight: 400;
|
||||
--body-line-height: 1.5;
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
--dark-border-subtle: #2b323b;
|
||||
|
||||
/* Typography & layout */
|
||||
--body-font-family: var(--optain-cassiopeia-font-family-body, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
|
||||
--body-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
--body-font-size: 1rem;
|
||||
--body-font-weight: 400;
|
||||
--body-line-height: 1.5;
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
--font-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--gradient: linear-gradient(180deg, #ffffff26, #fff0);
|
||||
--body-font-family: var(--optain-cassiopeia-font-family-body, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
|
||||
--body-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
|
||||
--body-font-size: 1rem;
|
||||
--body-font-weight: 400;
|
||||
--body-line-height: 1.5;
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
--font-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--gradient: linear-gradient(180deg, #ffffff26, #fff0);
|
||||
--body-font-family: var(--optain-cassiopeia-font-family-body, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
|
||||
--body-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
|
||||
--body-font-size: 1rem;
|
||||
--body-font-weight: 400;
|
||||
--body-line-height: 1.5;
|
||||
|
||||
@@ -1,556 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
/* 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
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
PATH: ./media/templates/site/moko-cassiopeia/css/gable.css
|
||||
VERSION: 03.05.00
|
||||
BRIEF: Stylesheet providing gable-specific layout and design rules for Moko-Cassiopeia
|
||||
*/
|
||||
|
||||
:root {
|
||||
--gab-blue: transparent;
|
||||
--gab-green: #7ac143;
|
||||
--gab-red: #3f8ff0;
|
||||
--gab-orange: #F9A541;
|
||||
--gab-gray1: #DDDDDD;
|
||||
--gab-gray2: #AAAAAA;
|
||||
--gab-gray3: #777777;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--gab-gray1);
|
||||
}
|
||||
|
||||
#view_gabble {
|
||||
background-color: var(--gab-blue);
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#mod_gabble {
|
||||
background-color: var(--gab-blue);
|
||||
padding: 3px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#lists_gabble {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
border: 4px solid var(--gab-red);
|
||||
background-color: var(--gab-green);
|
||||
padding: 4px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#select_list {
|
||||
margin-left: 0px;
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
border-radius: 6px 6px 0px 0px;
|
||||
}
|
||||
|
||||
#options_list {
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#frame_list {
|
||||
width: 100%;
|
||||
height: 484px;
|
||||
padding: 4px;
|
||||
border-radius: 0px 0px 6px 6px;
|
||||
}
|
||||
|
||||
#windows_list {
|
||||
margin-left: 0px;
|
||||
width: 100%;
|
||||
border: 4px solid var(--gab-red);
|
||||
background-color: var(--gab-green);
|
||||
padding: 4px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#frame_window {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#openai_btn {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
visibility: hidden;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
cursor: pointer;
|
||||
border: 3px solid var(--gab-gray3);
|
||||
background-color: #FFF;
|
||||
border-radius: 17px;
|
||||
}
|
||||
|
||||
#openai_btn:hover {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 3px solid var(--gab-gray3);
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
#openai_logo_anim {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
padding: 2px;
|
||||
z-index: 1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.openai_logo_sm {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-color: #FFF;
|
||||
border: 3px solid #FFF;
|
||||
border-radius: 11px;
|
||||
}
|
||||
|
||||
.openai_logo_md {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
background-color: #FFF;
|
||||
border: 4px solid #FFF;
|
||||
border-radius: 17px;
|
||||
}
|
||||
|
||||
.btn_on_com {
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: -2px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #448344;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn_on_mod {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #448344;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.button_list {
|
||||
border: none;
|
||||
width:100%;
|
||||
outline: none;
|
||||
background-color: var(--gab-gray1);
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.button_list:hover {
|
||||
background-color: var(--gab-gray2);
|
||||
}
|
||||
|
||||
.button_list_s {
|
||||
border: none;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: #FFF;
|
||||
background-color: var(--gab-red);
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.window_list {
|
||||
position: relative;
|
||||
margin: 4px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
background-color: var(--gab-gray1);
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.window_list:hover {
|
||||
background-color: var(--gab-gray2);
|
||||
}
|
||||
|
||||
.window_list_s {
|
||||
position: relative;
|
||||
margin: 4px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
color: #FFF;
|
||||
background-color: var(--gab-red);
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn_close {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 10px;
|
||||
padding-left: 1px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #000;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
background-color: var(--gab-gray2);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.btn_close:hover {
|
||||
background-color: var(--gab-gray3);
|
||||
}
|
||||
|
||||
.iframe_list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #FFF;
|
||||
border: 4px solid var(--gab-red);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.iframe_messages {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #FFF;
|
||||
border: 4px solid var(--gab-red);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.input_box {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input_emoji {
|
||||
position: absolute;
|
||||
right: 48px;
|
||||
top: 11px;
|
||||
cursor: pointer;
|
||||
color: var(--gab-gray2);
|
||||
}
|
||||
|
||||
.input_emoji:hover {
|
||||
color: var(--gab-gray3);
|
||||
}
|
||||
|
||||
.emoji {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.emoji:hover {
|
||||
background-color: var(--gab-orange);
|
||||
}
|
||||
|
||||
.emojis_div {
|
||||
position: absolute;
|
||||
top: -92px;
|
||||
right: 0px;
|
||||
width: 200px;
|
||||
height: 92px;
|
||||
border: 4px solid var(--gab-red);
|
||||
background-color: var(--gab-gray1);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.msg-button-on {
|
||||
margin-left: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
background-color: var(--gab-orange);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.msg-button-off {
|
||||
margin-left: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
background-color: var(--gab-gray2);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.taba-content {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.msg-input {
|
||||
padding-left: 10px;
|
||||
padding-right: 26px;
|
||||
width: calc(100% - 35px);
|
||||
height: 30px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.main-windows {
|
||||
position: fixed;
|
||||
margin-bottom: 10px;
|
||||
bottom: 0px;
|
||||
right: 90px;
|
||||
z-index: 901;
|
||||
}
|
||||
|
||||
.list-windows {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
width: 50px;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 20px;
|
||||
z-index: 901;
|
||||
}
|
||||
|
||||
.item-list {
|
||||
display: inline-block;
|
||||
color: #F5F5F5;
|
||||
margin-top: 5px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
border: 3px solid var(--gab-red);
|
||||
background-color: var(--gab-blue);
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
cursor: pointer;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.n-notifications {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
right: -2px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: #FFF;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background-color: #a51f18;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.m-notifications {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -2px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: #FFF;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background-color: #a51f18;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.window {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
width: 280px;
|
||||
height: 420px;
|
||||
}
|
||||
|
||||
.window-com {
|
||||
margin-top: 6px;
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
}
|
||||
|
||||
.window-title {
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.window-title-com {
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.window-icon {
|
||||
display: inline-block;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.window-header {
|
||||
padding: 6px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: var(--gab-blue);
|
||||
border-radius: 8px 8px 0px 0px;
|
||||
}
|
||||
|
||||
.window-header-com {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
background-color: var(--gab-red);
|
||||
border-radius: 8px 8px 0px 0px;
|
||||
}
|
||||
|
||||
.window-content {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(100% - 80px);
|
||||
background-color: #DDD;
|
||||
}
|
||||
|
||||
.content-footer {
|
||||
position: relative;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: #DDD;
|
||||
border-radius: 0px 0px 8px 8px;
|
||||
}
|
||||
|
||||
.taba-btn {
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
float: right;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: #DDD;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.taba-hover {
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.taba-hover:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.taba-self {
|
||||
border: 1px solid #FFF;
|
||||
background-color: #7ac143;
|
||||
padding: 6px;
|
||||
padding-top: 9px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.taba-others {
|
||||
border: 1px solid #FFF;
|
||||
background-color: #5091cd;
|
||||
padding: 6px;
|
||||
padding-top: 9px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.taba-bot {
|
||||
border: 1px solid #FFF;
|
||||
background-color: var(--gab-gray3);
|
||||
padding: 6px;
|
||||
padding-top: 9px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.taba-dice {
|
||||
border: 1px solid #FFF;
|
||||
background-color: #f44321;
|
||||
padding: 6px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.taba-emoji {
|
||||
border: 1px solid #FFF;
|
||||
background-color: #5091cd;
|
||||
padding: 6px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.taba-user {
|
||||
border: 1px solid #FFF;
|
||||
background-color: #FFF;
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.taba-user-on {
|
||||
border: 1px solid #FFF;
|
||||
background-color: var(--gab-green);
|
||||
padding: 6px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.taba-feed {
|
||||
border: 1px solid #FFF;
|
||||
background-color: var(--gab-blue);
|
||||
padding: 6px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.openai_error {
|
||||
border: 1px solid #FFF;
|
||||
background-color: var(--gab-red);
|
||||
padding: 6px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.taba-msgsystem {
|
||||
border: 1px solid #FFF;
|
||||
background-color: #AAA;
|
||||
padding: 6px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.taba-msghead {
|
||||
background-color: #f5f5f5;
|
||||
padding: 4px;
|
||||
padding-left: 10px;
|
||||
padding-right: 6px;
|
||||
border-radius: 6px 6px 0px 0px;
|
||||
}
|
||||
|
||||
.taba-msg {
|
||||
background-color: #f5f5f5;
|
||||
padding: 8px;
|
||||
border-radius: 0px 8px 8px 8px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
/* 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
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
PATH: ./media/templates/site/moko-cassiopeia/css/global/social-media-demo.css
|
||||
VERSION: 03.05.00
|
||||
BRIEF: Demo styles for showcasing social media elements in Moko-Cassiopeia template
|
||||
*/
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
Social Media Demo — FULL CSS (Joomla-safe, fully scoped)
|
||||
Scope: All selectors prefixed with .social-media-demo to avoid leakage
|
||||
Usage: Wrap your article markup in <div class="social-media-demo"> ... </div>
|
||||
Version: 2.0 (2025-08-23)
|
||||
|
||||
How it’s organized:
|
||||
1) Container-level CSS variables (IMAGES ONLY). Colors are hard-coded per brand below.
|
||||
2) Base/layout styles (sections, header shell, placeholders, buttons).
|
||||
3) Platform brand colors (hard-coded) and cover height tweaks.
|
||||
4) Image assignments (map classes like .fb-cover → variable --fb-cover-img).
|
||||
|
||||
INSTRUCTIONS:
|
||||
- Save the images in their requried sizes into the [SITEROOT]/images/social/ folder with the exact names.
|
||||
- For circle images, sue a square image t fille the entire space
|
||||
- All images are center and miiddle aligned when loaded.
|
||||
======================================================================
|
||||
REQUIRED IMAGE SIZES — Social Media Demo Wireframes
|
||||
|
||||
Facebook
|
||||
--fb-cover-img → Cover: 820×312 (desktop), 640×360 (mobile safe)
|
||||
--fb-avatar-img → Profile: 176×176 (shown as circle, but use square image)
|
||||
|
||||
Twitter / X
|
||||
--x-cover-img → Header: 1500×500
|
||||
--x-avatar-img → Profile: up to 400×400 (shown as circle, but use square image)
|
||||
|
||||
LinkedIn Company
|
||||
--li-cover-img → Banner: ~1128×191
|
||||
--li-logo-img → Logo: up to 300×300 (rounded square)
|
||||
|
||||
Google Business Profile
|
||||
--gmb-cover-img → Banner: ~960×200 (mobile ~960×140)
|
||||
--gmb-logo-img → Logo: up to 300×300 (shown as circle, but use square image)
|
||||
|
||||
Instagram Business
|
||||
--ig-cover-img → Not always visible, safe 1080×608 for highlight background
|
||||
--ig-avatar-img → Profile: 320×320 (shown as circle, but use square image)
|
||||
|
||||
YouTube Channel
|
||||
--yt-cover-img → Channel art: 2560×1440 (safe area ~1546×423 center)
|
||||
--yt-avatar-img → Channel icon: 800×800 (shown as circle, but use square image)
|
||||
|
||||
TikTok Business
|
||||
--tt-cover-img → Profile header: ~900×500 (safe area ~720×405)
|
||||
--tt-avatar-img → Profile: 200×200 (shown as circle, but use square image)
|
||||
|
||||
Pinterest Business
|
||||
--pin-cover-img → Board/brand banner: ~800×450
|
||||
--pin-avatar-img → Profile: 165×165 (shown as circle, but use square image)
|
||||
|
||||
Snapchat Public Profile
|
||||
--sc-cover-img → Banner: ~1080×1920 (stories/poster)
|
||||
--sc-avatar-img → Bitmoji/Profile: 320×320 (shown as circle, but use square image)
|
||||
|
||||
Reddit Community
|
||||
--rd-cover-img → Banner: 1920×384
|
||||
--rd-avatar-img → Community icon: 256×256 (shown as circle, but use square image)
|
||||
====================================================================== */
|
||||
|
||||
/* Container variables — IMAGES ONLY (safe-scoped) */
|
||||
.social-media-demo {
|
||||
--fb-cover-img: url('../../../../../image/social/fb-cover.jpg');
|
||||
--fb-avatar-img: url('../../../../../image/social/fb-avatar.jpg');
|
||||
|
||||
--x-cover-img: url('../../../../../image/social/x-cover.jpg');
|
||||
--x-avatar-img: url('../../../../../image/social/x-avatar.jpg');
|
||||
|
||||
--li-cover-img: url('../../../../../image/social/li-cover.jpg');
|
||||
--li-logo-img: url('../../../../../image/social/li-logo.jpg');
|
||||
|
||||
--gmb-cover-img: url('../../../../../image/social/gmb-cover.jpg');
|
||||
--gmb-logo-img: url('../../../../../image/social/gmb-logo.jpg');
|
||||
|
||||
--ig-cover-img: url('../../../../../image/social/ig-cover.jpg');
|
||||
--ig-avatar-img: url('../../../../../image/social/ig-avatar.jpg');
|
||||
|
||||
--yt-cover-img: url('../../../../../image/social/yt-cover.jpg');
|
||||
--yt-avatar-img: url('../../../../../image/social/yt-avatar.jpg');
|
||||
|
||||
--tt-cover-img: url('../../../../../image/social/tt-cover.jpg');
|
||||
--tt-avatar-img: url('../../../../../image/social/tt-avatar.jpg');
|
||||
|
||||
--pin-cover-img: url('../../../../../image/social/pin-cover.jpg');
|
||||
--pin-avatar-img: url('../../../../../image/social/pin-avatar.jpg');
|
||||
|
||||
--sc-cover-img: url('../../../../../image/social/sc-cover.jpg');
|
||||
--sc-avatar-img: url('../../../../../image/social/sc-avatar.jpg');
|
||||
|
||||
--rd-cover-img: url('../../../../../image/social/rd-cover.jpg');
|
||||
--rd-avatar-img: url('../../../../../image/social/rd-avatar.jpg');
|
||||
}
|
||||
|
||||
/* DO NOT TOUCH */
|
||||
.social-media-demo * { box-sizing: border-box; }
|
||||
.social-media-demo section { margin: 24px auto; max-width: 1128px; background: #fff; border: 1px solid #d9dee3; border-radius: 12px; overflow: hidden; }
|
||||
.social-media-demo section h2 { margin: 0; padding: 12px 16px; background: #f9fafb; border-bottom: 1px solid #d9dee3; font-size: 16px; font-weight: 800; color: #111; }
|
||||
.social-media-demo .preview { padding: 16px; }
|
||||
|
||||
/* Header shell */
|
||||
.social-media-demo .header { position: relative; border: 1px solid #d9dee3; border-radius: 12px; overflow: hidden; background: #fff; }
|
||||
.social-media-demo .cover { position: relative; width: 100%; height: 200px; background-size: cover; background-position: center; background-color: #e8edf3; }
|
||||
.social-media-demo .avatar-wrap { position: absolute; left: 16px; bottom: -48px; }
|
||||
.social-media-demo .avatar,
|
||||
.social-media-demo .logo { width: 160px; height: 160px; border: 4px solid #fff; background-size: cover; background-position: center; overflow: hidden; }
|
||||
.social-media-demo .avatar.shown as circle, but use square image { border-radius: 999px; }
|
||||
.social-media-demo .logo.rounded { border-radius: 16px; }
|
||||
|
||||
/* Meta */
|
||||
.social-media-demo .meta { display: flex; justify-content: space-between; align-items: end; gap: 16px; padding: 16px; padding-top: 56px; }
|
||||
.social-media-demo .name { font-size: 22px; font-weight: 800; color: #111; }
|
||||
.social-media-demo .subline { font-size: 13px; color: #666; }
|
||||
|
||||
/* Buttons */
|
||||
.social-media-demo .btn { display: inline-flex; align-items: center; height: 32px; padding: 0 12px; border-radius: 8px; border: 1px solid #d9dee3; background: #fff; font-weight: 700; color: #111; }
|
||||
.social-media-demo .btn.primary { color: #fff; border-color: transparent; }
|
||||
|
||||
/* Placeholder visuals (used until you swap in real images) */
|
||||
.social-media-demo .placeholder { position: relative; width: 100%; height: 100%; display: grid; place-items: center; text-align: center; font-weight: 600; color: #6b7280; background: repeating-linear-gradient(45deg,#f6f7f9 0 12px,#eef0f3 12px 24px); border: 1px dashed #cfd3d8; }
|
||||
.social-media-demo .placeholder .dims { position: absolute; bottom: 8px; right: 8px; font-size: 12px; opacity: .85; }
|
||||
|
||||
/* 3) Platform brand colors & cover height tweaks (hard-coded colors on purpose) */
|
||||
/* Facebook */
|
||||
.social-media-demo #fb .btn.primary { background: #1877F2; }
|
||||
.social-media-demo #fb .cover { height: 312px; }
|
||||
@media (max-width: 480px) { .social-media-demo #fb .cover { height: 360px; } }
|
||||
|
||||
/* Twitter / X */
|
||||
.social-media-demo #x .btn.primary { background: #1D9BF0; }
|
||||
.social-media-demo #x .cover { height: 200px; background-color: #22303C; }
|
||||
@media (max-width: 480px) { .social-media-demo #x .cover { height: 160px; } }
|
||||
|
||||
/* LinkedIn */
|
||||
.social-media-demo #li .btn.primary { background: #0A66C2; }
|
||||
.social-media-demo #li .cover { height: 220px; background-color: #e6edf5; }
|
||||
@media (max-width: 480px) { .social-media-demo #li .cover { height: 160px; } }
|
||||
|
||||
/* Google Business Profile */
|
||||
.social-media-demo #gmb .btn.primary { background: #4285F4; }
|
||||
.social-media-demo #gmb .cover { height: 200px; }
|
||||
@media (max-width: 480px) { .social-media-demo #gmb .cover { height: 140px; } }
|
||||
|
||||
/* Instagram Business */
|
||||
.social-media-demo #ig .btn.primary { background: #E1306C; }
|
||||
.social-media-demo #ig .cover { height: 200px; }
|
||||
|
||||
/* YouTube Channel */
|
||||
.social-media-demo #yt .btn.primary { background: #FF0000; }
|
||||
.social-media-demo #yt .cover { height: 180px; }
|
||||
|
||||
/* TikTok Business */
|
||||
.social-media-demo #tt .btn.primary { background: #000000; color: #fff; }
|
||||
.social-media-demo #tt .cover { height: 200px; }
|
||||
|
||||
/* Pinterest Business */
|
||||
.social-media-demo #pin .btn.primary { background: #E60023; }
|
||||
.social-media-demo #pin .cover { height: 200px; }
|
||||
|
||||
/* Snapchat Public Profile */
|
||||
.social-media-demo #sc .btn.primary { background: #FFFC00; color: #000; }
|
||||
.social-media-demo #sc .cover { height: 160px; }
|
||||
|
||||
/* Reddit Community */
|
||||
.social-media-demo #rd .btn.primary { background: #FF4500; }
|
||||
.social-media-demo #rd .cover { height: 180px; }
|
||||
|
||||
/* 4) Image assignments — map classes to variables (swap vars to change images) */
|
||||
/* Facebook */
|
||||
.social-media-demo .fb-cover { background-image: var(--fb-cover-img); }
|
||||
.social-media-demo .fb-avatar { background-image: var(--fb-avatar-img); }
|
||||
|
||||
/* X */
|
||||
.social-media-demo .x-cover { background-image: var(--x-cover-img); }
|
||||
.social-media-demo .x-avatar { background-image: var(--x-avatar-img); }
|
||||
|
||||
/* LinkedIn */
|
||||
.social-media-demo .li-cover { background-image: var(--li-cover-img); }
|
||||
.social-media-demo .li-logo { background-image: var(--li-logo-img); }
|
||||
|
||||
/* Google Business */
|
||||
.social-media-demo .gmb-cover { background-image: var(--gmb-cover-img); }
|
||||
.social-media-demo .gmb-logo { background-image: var(--gmb-logo-img); }
|
||||
|
||||
/* Instagram */
|
||||
.social-media-demo .ig-cover { background-image: var(--ig-cover-img); }
|
||||
.social-media-demo .ig-avatar { background-image: var(--ig-avatar-img); }
|
||||
|
||||
/* YouTube */
|
||||
.social-media-demo .yt-cover { background-image: var(--yt-cover-img); }
|
||||
.social-media-demo .yt-avatar { background-image: var(--yt-avatar-img); }
|
||||
|
||||
/* TikTok */
|
||||
.social-media-demo .tt-cover { background-image: var(--tt-cover-img); }
|
||||
.social-media-demo .tt-avatar { background-image: var(--tt-avatar-img); }
|
||||
|
||||
/* Pinterest */
|
||||
.social-media-demo .pin-cover { background-image: var(--pin-cover-img); }
|
||||
.social-media-demo .pin-avatar { background-image: var(--pin-avatar-img); }
|
||||
|
||||
/* Snapchat */
|
||||
.social-media-demo .sc-cover { background-image: var(--sc-cover-img); }
|
||||
.social-media-demo .sc-avatar { background-image: var(--sc-avatar-img); }
|
||||
|
||||
/* Reddit */
|
||||
.social-media-demo .rd-cover { background-image: var(--rd-cover-img); }
|
||||
.social-media-demo .rd-avatar { background-image: var(--rd-avatar-img); }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
VERSION: 03.05.00
|
||||
BRIEF: Core JavaScript utilities and behaviors for Moko-Cassiopeia template
|
||||
*/
|
||||
|
||||
!function(a){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var n=e.find(t);return e.filter(t).add(n).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(e){return a(e).text().trim().replace(/\'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,64).replace(/^-+|-+$/gm,"").toLowerCase()||e.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),n=0;;n++){var r=t;if(0<n&&(r+="-"+n),!document.getElementById(r))return r}},generateAnchor:function(e){if(e.id)return e.id;var t=this.generateUniqueId(e);return e.id=t},createNavList:function(){return a('<ul class="nav navbar-nav"></ul>')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var n=a('<a class="nav-link"></a>');n.attr("href","#"+e),n.text(t);var r=a("<li></li>");return r.append(n),r},generateNavItem:function(e){var t=this.generateAnchor(e),n=a(e),r=n.data("toc-text")||n.text();return this.generateNavEl(t,r)},getTopLevel:function(e){for(var t=1;t<=6;t++){if(1<this.findOrFilter(e,"h"+t).length)return t}return 1},getHeadings:function(e,t){var n="h"+t,r="h"+(t+1);return this.findOrFilter(e,n+","+r)},getNavLevel:function(e){return parseInt(e.tagName.charAt(1),10)},populateNav:function(r,a,e){var i,s=r,c=this;e.each(function(e,t){var n=c.generateNavItem(t);c.getNavLevel(t)===a?s=r:i&&s===r&&(s=c.createChildNavList(i)),s.append(n),i=n})},parseOps:function(e){var t;return(t=e.jquery?{$nav:e}:e).$scope=t.$scope||a(document.body),t}},init:function(e){(e=this.helpers.parseOps(e)).$nav.attr("data-toggle","toc");var t=this.helpers.createChildNavList(e.$nav),n=this.helpers.getTopLevel(e.$scope),r=this.helpers.getHeadings(e.$scope,n);this.helpers.populateNav(t,n,r)}},a(function(){a('nav[data-toggle="toc"]').each(function(e,t){var n=a(t);Toc.init(n)})})}(jQuery);
|
||||
(function (win, doc) {
|
||||
"use strict";
|
||||
|
||||
|
||||
21
src/media/js/user.js
Normal file
21
src/media/js/user.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/* 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
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/ .
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
PATH: ./media/templates/site/moko-cassiopeia/js/user.js
|
||||
VERSION: 03.00.00
|
||||
BRIEF: JavaScript for handling user-specific interactions in Moko-Cassiopeia template
|
||||
*/
|
||||
4
src/media/vendor/afeld/bootstrap-toc.min.css
vendored
4
src/media/vendor/afeld/bootstrap-toc.min.css
vendored
@@ -1,4 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Table of Contents v1.0.1 (http://afeld.github.io/bootstrap-toc/)
|
||||
* Copyright 2015 Aidan Feldman
|
||||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */nav[data-toggle=toc] .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}nav[data-toggle=toc] .nav>li>a:focus,nav[data-toggle=toc] .nav>li>a:hover{padding-left:19px;color:#563d7c;text-decoration:none;background-color:transparent;border-left:1px solid #563d7c}nav[data-toggle=toc] .nav-link.active,nav[data-toggle=toc] .nav-link.active:focus,nav[data-toggle=toc] .nav-link.active:hover{padding-left:18px;font-weight:700;color:#563d7c;background-color:transparent;border-left:2px solid #563d7c}nav[data-toggle=toc] .nav-link+ul{display:none;padding-bottom:10px}nav[data-toggle=toc] .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}nav[data-toggle=toc] .nav .nav>li>a:focus,nav[data-toggle=toc] .nav .nav>li>a:hover{padding-left:29px}nav[data-toggle=toc] .nav .nav>li>.active,nav[data-toggle=toc] .nav .nav>li>.active:focus,nav[data-toggle=toc] .nav .nav>li>.active:hover{padding-left:28px;font-weight:500}nav[data-toggle=toc] .nav-link.active+ul{display:block}
|
||||
5
src/media/vendor/afeld/bootstrap-toc.min.js
vendored
5
src/media/vendor/afeld/bootstrap-toc.min.js
vendored
@@ -1,5 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Table of Contents v1.0.1 (http://afeld.github.io/bootstrap-toc/)
|
||||
* Copyright 2015 Aidan Feldman
|
||||
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
|
||||
!function(a){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var n=e.find(t);return e.filter(t).add(n).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(e){return a(e).text().trim().replace(/\'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,64).replace(/^-+|-+$/gm,"").toLowerCase()||e.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),n=0;;n++){var r=t;if(0<n&&(r+="-"+n),!document.getElementById(r))return r}},generateAnchor:function(e){if(e.id)return e.id;var t=this.generateUniqueId(e);return e.id=t},createNavList:function(){return a('<ul class="nav navbar-nav"></ul>')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var n=a('<a class="nav-link"></a>');n.attr("href","#"+e),n.text(t);var r=a("<li></li>");return r.append(n),r},generateNavItem:function(e){var t=this.generateAnchor(e),n=a(e),r=n.data("toc-text")||n.text();return this.generateNavEl(t,r)},getTopLevel:function(e){for(var t=1;t<=6;t++){if(1<this.findOrFilter(e,"h"+t).length)return t}return 1},getHeadings:function(e,t){var n="h"+t,r="h"+(t+1);return this.findOrFilter(e,n+","+r)},getNavLevel:function(e){return parseInt(e.tagName.charAt(1),10)},populateNav:function(r,a,e){var i,s=r,c=this;e.each(function(e,t){var n=c.generateNavItem(t);c.getNavLevel(t)===a?s=r:i&&s===r&&(s=c.createChildNavList(i)),s.append(n),i=n})},parseOps:function(e){var t;return(t=e.jquery?{$nav:e}:e).$scope=t.$scope||a(document.body),t}},init:function(e){(e=this.helpers.parseOps(e)).$nav.attr("data-toggle","toc");var t=this.helpers.createChildNavList(e.$nav),n=this.helpers.getTopLevel(e.$scope),r=this.helpers.getHeadings(e.$scope,n);this.helpers.populateNav(t,n,r)}},a(function(){a('nav[data-toggle="toc"]').each(function(e,t){var n=a(t);Toc.init(n)})})}(jQuery);
|
||||
513
src/media/vendor/choicesjs/choices.css
vendored
513
src/media/vendor/choicesjs/choices.css
vendored
@@ -1,513 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
/* 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
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
PATH: ./media/templates/site/moko-cassiopeia/css/vendor/choicesjs/choices.css
|
||||
VERSION: 03.00.00
|
||||
BRIEF: Vendor stylesheet for Choices.js select and input enhancements in Moko-Cassiopeia
|
||||
*/
|
||||
|
||||
/* ===============================
|
||||
= Choices =
|
||||
=============================== */
|
||||
.choices {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.choices:focus {
|
||||
outline: none;
|
||||
}
|
||||
.choices:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.choices.is-open {
|
||||
overflow: initial;
|
||||
}
|
||||
.choices.is-disabled .choices__inner,
|
||||
.choices.is-disabled .choices__input {
|
||||
background-color: #eaeaea;
|
||||
cursor: not-allowed;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.choices.is-disabled .choices__item {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.choices [hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.choices[data-type*=select-one] {
|
||||
cursor: pointer;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__inner {
|
||||
padding-bottom: 7.5px;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==");
|
||||
padding: 0;
|
||||
background-size: 8px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
margin-top: -10px;
|
||||
margin-right: 25px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 10em;
|
||||
opacity: 0.25;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button:hover, .choices[data-type*=select-one] .choices__button:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button:focus {
|
||||
-webkit-box-shadow: 0 0 0 2px #00bcd4;
|
||||
box-shadow: 0 0 0 2px #00bcd4;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__item[data-value=""] .choices__button {
|
||||
display: none;
|
||||
}
|
||||
.choices[data-type*=select-one]::after {
|
||||
content: "";
|
||||
height: 0;
|
||||
width: 0;
|
||||
border-style: solid;
|
||||
border-color: #333 transparent transparent transparent;
|
||||
border-width: 5px;
|
||||
position: absolute;
|
||||
right: 11.5px;
|
||||
top: 50%;
|
||||
margin-top: -2.5px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.choices[data-type*=select-one].is-open::after {
|
||||
border-color: transparent transparent #333 transparent;
|
||||
margin-top: -7.5px;
|
||||
}
|
||||
.choices[data-type*=select-one][dir=rtl]::after {
|
||||
left: 11.5px;
|
||||
right: auto;
|
||||
}
|
||||
.choices[data-type*=select-one][dir=rtl] .choices__button {
|
||||
right: auto;
|
||||
left: 0;
|
||||
margin-left: 25px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.choices[data-type*=select-multiple] .choices__inner,
|
||||
.choices[data-type*=text] .choices__inner {
|
||||
cursor: text;
|
||||
}
|
||||
.choices[data-type*=select-multiple] .choices__button,
|
||||
.choices[data-type*=text] .choices__button {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-top: 0;
|
||||
margin-right: -4px;
|
||||
margin-bottom: 0;
|
||||
margin-left: 8px;
|
||||
padding-left: 16px;
|
||||
border-left: 1px solid #008fa1;
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==");
|
||||
background-size: 8px;
|
||||
width: 8px;
|
||||
line-height: 1;
|
||||
opacity: 0.75;
|
||||
border-radius: 0;
|
||||
}
|
||||
.choices[data-type*=select-multiple] .choices__button:hover, .choices[data-type*=select-multiple] .choices__button:focus,
|
||||
.choices[data-type*=text] .choices__button:hover,
|
||||
.choices[data-type*=text] .choices__button:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.choices__inner {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
background-color: #f9f9f9;
|
||||
padding: 7.5px 7.5px 3.75px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2.5px;
|
||||
font-size: 14px;
|
||||
min-height: 44px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.is-focused .choices__inner, .is-open .choices__inner {
|
||||
border-color: #b7b7b7;
|
||||
}
|
||||
.is-open .choices__inner {
|
||||
border-radius: 2.5px 2.5px 0 0;
|
||||
}
|
||||
.is-flipped.is-open .choices__inner {
|
||||
border-radius: 0 0 2.5px 2.5px;
|
||||
}
|
||||
|
||||
.choices__list {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.choices__list--single {
|
||||
display: inline-block;
|
||||
padding: 4px 16px 4px 4px;
|
||||
width: 100%;
|
||||
}
|
||||
[dir=rtl] .choices__list--single {
|
||||
padding-right: 4px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.choices__list--single .choices__item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.choices__list--multiple {
|
||||
display: inline;
|
||||
}
|
||||
.choices__list--multiple .choices__item {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-radius: 20px;
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
margin-right: 3.75px;
|
||||
margin-bottom: 3.75px;
|
||||
background-color: #00bcd4;
|
||||
border: 1px solid #00a5bb;
|
||||
color: #fff;
|
||||
word-break: break-all;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.choices__list--multiple .choices__item[data-deletable] {
|
||||
padding-right: 5px;
|
||||
}
|
||||
[dir=rtl] .choices__list--multiple .choices__item {
|
||||
margin-right: 0;
|
||||
margin-left: 3.75px;
|
||||
}
|
||||
.choices__list--multiple .choices__item.is-highlighted {
|
||||
background-color: #00a5bb;
|
||||
border: 1px solid #008fa1;
|
||||
}
|
||||
.is-disabled .choices__list--multiple .choices__item {
|
||||
background-color: #aaaaaa;
|
||||
border: 1px solid #919191;
|
||||
}
|
||||
|
||||
.choices__list--dropdown {
|
||||
visibility: hidden;
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
top: 100%;
|
||||
margin-top: -1px;
|
||||
border-bottom-left-radius: 2.5px;
|
||||
border-bottom-right-radius: 2.5px;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
will-change: visibility;
|
||||
}
|
||||
.choices__list--dropdown.is-active {
|
||||
visibility: visible;
|
||||
}
|
||||
.is-open .choices__list--dropdown {
|
||||
border-color: #b7b7b7;
|
||||
}
|
||||
.is-flipped .choices__list--dropdown {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
margin-top: 0;
|
||||
margin-bottom: -1px;
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
}
|
||||
.choices__list--dropdown .choices__list {
|
||||
position: relative;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
will-change: scroll-position;
|
||||
}
|
||||
.choices__list--dropdown .choices__item {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
[dir=rtl] .choices__list--dropdown .choices__item {
|
||||
text-align: right;
|
||||
}
|
||||
@media (min-width: 640px) {
|
||||
.choices__list--dropdown .choices__item--selectable {
|
||||
padding-right: 100px;
|
||||
}
|
||||
.choices__list--dropdown .choices__item--selectable::after {
|
||||
content: attr(data-select-text);
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
[dir=rtl] .choices__list--dropdown .choices__item--selectable {
|
||||
text-align: right;
|
||||
padding-left: 100px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
[dir=rtl] .choices__list--dropdown .choices__item--selectable::after {
|
||||
right: auto;
|
||||
left: 10px;
|
||||
}
|
||||
}
|
||||
.choices__list--dropdown .choices__item--selectable.is-highlighted {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
.choices__list--dropdown .choices__item--selectable.is-highlighted::after {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.choices__item {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.choices__item--selectable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.choices__item--disabled {
|
||||
cursor: not-allowed;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.choices__heading {
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #f7f7f7;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.choices__button {
|
||||
text-indent: -9999px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.choices__button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.choices__input {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
background-color: #f9f9f9;
|
||||
font-size: 14px;
|
||||
margin-bottom: 5px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
max-width: 100%;
|
||||
padding: 4px 0 4px 2px;
|
||||
}
|
||||
.choices__input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
[dir=rtl] .choices__input {
|
||||
padding-right: 2px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.choices__placeholder {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* ===== End of Choices ====== */
|
||||
.choices {
|
||||
border: 1px solid hsl(210, 14%, 83%);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
.choices.is-focused {
|
||||
border-color: #8894aa;
|
||||
-webkit-box-shadow: 0 0 0 0.25rem rgba(1, 1, 86, 0.25);
|
||||
box-shadow: 0 0 0 0.25rem rgba(1, 1, 86, 0.25);
|
||||
}
|
||||
|
||||
.choices__inner {
|
||||
padding: 0.4rem 1rem;
|
||||
margin-bottom: 0;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.choices__input {
|
||||
padding: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 1rem;
|
||||
background-color: transparent;
|
||||
}
|
||||
.choices__input::-webkit-input-placeholder {
|
||||
color: hsl(210, 9%, 31%);
|
||||
opacity: 1;
|
||||
}
|
||||
.choices__input::-moz-placeholder {
|
||||
color: hsl(210, 9%, 31%);
|
||||
opacity: 1;
|
||||
}
|
||||
.choices__input:-ms-input-placeholder {
|
||||
color: hsl(210, 9%, 31%);
|
||||
opacity: 1;
|
||||
}
|
||||
.choices__input::-ms-input-placeholder {
|
||||
color: hsl(210, 9%, 31%);
|
||||
opacity: 1;
|
||||
}
|
||||
.choices__input::placeholder {
|
||||
color: hsl(210, 9%, 31%);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.choices__list--dropdown {
|
||||
z-index: 1060;
|
||||
}
|
||||
|
||||
.choices__list--multiple .choices__item {
|
||||
position: relative;
|
||||
margin: 2px;
|
||||
background-color: var(--color-primary);
|
||||
-webkit-margin-end: 2px;
|
||||
margin-inline-end: 2px;
|
||||
border: 0;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
.choices__list--multiple .choices__item.is-highlighted {
|
||||
background-color: var(--color-primary);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.choices .choices__list--dropdown .choices__item {
|
||||
-webkit-padding-end: 10px;
|
||||
padding-inline-end: 10px;
|
||||
}
|
||||
.choices .choices__list--dropdown .choices__item--selectable::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.choices__button_joomla {
|
||||
position: relative;
|
||||
padding: 0 10px;
|
||||
color: inherit;
|
||||
text-indent: -9999px;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: 0;
|
||||
opacity: 0.5;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
.choices__button_joomla::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-indent: 0;
|
||||
content: "×";
|
||||
}
|
||||
.choices__button_joomla:hover, .choices__button_joomla:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
.choices__button_joomla:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.choices[data-type*=select-one] .choices__inner,
|
||||
.choices[data-type*=select-multiple] .choices__inner {
|
||||
-webkit-padding-end: 3rem;
|
||||
padding-inline-end: 3rem;
|
||||
cursor: pointer;
|
||||
background: url("../../../images/select-bg.svg") no-repeat 100%/116rem;
|
||||
background-color: hsl(210, 16%, 93%);
|
||||
}
|
||||
[dir=rtl] .choices[data-type*=select-one] .choices__inner,
|
||||
[dir=rtl] .choices[data-type*=select-multiple] .choices__inner {
|
||||
background: url("../../../images/select-bg-rtl.svg") no-repeat 0/116rem;
|
||||
background-color: hsl(210, 16%, 93%);
|
||||
}
|
||||
|
||||
.choices[data-type*=select-one] .choices__item {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button_joomla {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
inset-inline-end: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
-webkit-margin-before: -10px;
|
||||
margin-block-start: -10px;
|
||||
-webkit-margin-end: 50px;
|
||||
margin-inline-end: 50px;
|
||||
border-radius: 10em;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button_joomla:hover, .choices[data-type*=select-one] .choices__button_joomla:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button_joomla:focus {
|
||||
-webkit-box-shadow: 0 0 0 2px #00bcd4;
|
||||
box-shadow: 0 0 0 2px #00bcd4;
|
||||
}
|
||||
.choices[data-type*=select-one]::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.choices[data-type*=select-multiple] .choices__input,
|
||||
.choices[data-type*=text] .choices__input {
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
|
||||
.choices__heading {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
81
src/media/vendor/choicesjs/index.html
vendored
81
src/media/vendor/choicesjs/index.html
vendored
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Site
|
||||
INGROUP: Templates.Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Site
|
||||
INGROUP: Templates.Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,161 +0,0 @@
|
||||
@charset "UTF-8";
|
||||
/* 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
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Template.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
PATH: ./media/templates/site/moko-cassiopeia/css/vendor/choicesjs/choices.css
|
||||
VERSION: 03.00.00
|
||||
BRIEF: Vendor stylesheet for Choices.js select and input enhancements in Moko-Cassiopeia
|
||||
*/
|
||||
|
||||
@import "../../../../../../vendor/joomla-custom-elements/css/joomla-alert.css";
|
||||
#system-message-container:empty {
|
||||
display: none;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#system-message-container joomla-alert {
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 16rem;
|
||||
padding: 0;
|
||||
margin-bottom: 0;
|
||||
color: var(--gray-dark);
|
||||
background-color: hsl(0, 0%, 100%);
|
||||
border: 1px solid var(--alert-accent-color, transparent);
|
||||
border-radius: 0.25rem;
|
||||
-webkit-transition: opacity 0.15s linear;
|
||||
-o-transition: opacity 0.15s linear;
|
||||
transition: opacity 0.15s linear;
|
||||
}
|
||||
#system-message-container joomla-alert + * {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
#system-message-container joomla-alert .alert-heading {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-ms-flex-line-pack: center;
|
||||
align-content: center;
|
||||
padding: 0.8rem;
|
||||
color: var(--alert-heading-text);
|
||||
background: var(--alert-accent-color, transparent);
|
||||
}
|
||||
#system-message-container joomla-alert .alert-heading .message::before,
|
||||
#system-message-container joomla-alert .alert-heading .success::before {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
content: "";
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path fill="rgba(255, 255, 255, .95)" d="M1299 813l-422 422q-19 19-45 19t-45-19l-294-294q-19-19-19-45t19-45l102-102q19-19 45-19t45 19l147 147 275-275q19-19 45-19t45 19l102 102q19 19 19 45t-19 45zm141 83q0-148-73-273t-198-198-273-73-273 73-198 198-73 273 73 273 198 198 273 73 273-73 198-198 73-273zm224 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/></svg>');
|
||||
background-size: 100%;
|
||||
}
|
||||
#system-message-container joomla-alert .alert-heading .notice::before,
|
||||
#system-message-container joomla-alert .alert-heading .info::before {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
content: "";
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="1792" height="1792" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path fill="rgba(255, 255, 255, .95)" d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"/></svg>');
|
||||
background-size: 100%;
|
||||
}
|
||||
#system-message-container joomla-alert .alert-heading .warning::before {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
content: "";
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path fill="rgba(255, 255, 255, .95)" d="M1024 1375v-190q0-14-9.5-23.5t-22.5-9.5h-192q-13 0-22.5 9.5t-9.5 23.5v190q0 14 9.5 23.5t22.5 9.5h192q13 0 22.5-9.5t9.5-23.5zm-2-374l18-459q0-12-10-19-13-11-24-11h-220q-11 0-24 11-10 7-10 21l17 457q0 10 10 16.5t24 6.5h185q14 0 23.5-6.5t10.5-16.5zm-14-934l768 1408q35 63-2 126-17 29-46.5 46t-63.5 17h-1536q-34 0-63.5-17t-46.5-46q-37-63-2-126l768-1408q17-31 47-49t65-18 65 18 47 49z"/></svg>');
|
||||
background-size: 100%;
|
||||
}
|
||||
#system-message-container joomla-alert .alert-heading .error::before,
|
||||
#system-message-container joomla-alert .alert-heading .danger::before {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
content: "";
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="1792" height="1792" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path fill="rgba(255, 255, 255, .95)" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z"/></svg>');
|
||||
background-size: 100%;
|
||||
}
|
||||
#system-message-container joomla-alert .alert-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
#system-message-container joomla-alert .alert-link {
|
||||
color: var(--success, inherit);
|
||||
}
|
||||
#system-message-container joomla-alert[type=success], #system-message-container joomla-alert[type=message] {
|
||||
--alert-accent-color: var(--success);
|
||||
--alert-heading-text: hsla(0, 0%, 100%, .95);
|
||||
--alert-close-button: var(--success);
|
||||
background-color: hsl(0, 0%, 100%);
|
||||
}
|
||||
#system-message-container joomla-alert[type=info], #system-message-container joomla-alert[type=notice] {
|
||||
--alert-accent-color: var(--info);
|
||||
--alert-heading-text: hsla(0, 0%, 100%, .95);
|
||||
--alert-close-button: var(--info);
|
||||
background-color: hsl(0, 0%, 100%);
|
||||
}
|
||||
#system-message-container joomla-alert[type=warning] {
|
||||
--alert-accent-color: var(--warning);
|
||||
--alert-heading-text: hsla(0, 0%, 100%, .95);
|
||||
--alert-close-button: var(--warning);
|
||||
background-color: hsl(0, 0%, 100%);
|
||||
}
|
||||
#system-message-container joomla-alert[type=error], #system-message-container joomla-alert[type=danger] {
|
||||
--alert-accent-color: var(--danger);
|
||||
--alert-heading-text: hsla(0, 0%, 100%, .95);
|
||||
--alert-close-button: var(--danger);
|
||||
background-color: hsl(0, 0%, 100%);
|
||||
}
|
||||
#system-message-container joomla-alert .joomla-alert--close,
|
||||
#system-message-container joomla-alert .joomla-alert-button--close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0.2rem 0.8rem;
|
||||
font-size: 2rem;
|
||||
color: var(--alert-close-button);
|
||||
background: none;
|
||||
border: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
#system-message-container joomla-alert .joomla-alert--close:hover, #system-message-container joomla-alert .joomla-alert--close:focus,
|
||||
#system-message-container joomla-alert .joomla-alert-button--close:hover,
|
||||
#system-message-container joomla-alert .joomla-alert-button--close:focus {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
opacity: 0.75;
|
||||
}
|
||||
[dir=rtl] #system-message-container joomla-alert .joomla-alert--close,
|
||||
[dir=rtl] #system-message-container joomla-alert .joomla-alert-button--close {
|
||||
right: auto;
|
||||
left: 0;
|
||||
padding: 0.2rem 0.6rem;
|
||||
}
|
||||
#system-message-container joomla-alert div {
|
||||
font-size: 1rem;
|
||||
}
|
||||
#system-message-container joomla-alert div .alert-message {
|
||||
padding: 0.3rem 2rem 0.3rem 0.3rem;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
[dir=rtl] #system-message-container joomla-alert div .alert-message {
|
||||
padding: 0.3rem 0.3rem 0.3rem 2rem;
|
||||
}
|
||||
#system-message-container joomla-alert div .alert-message:not(:first-of-type) {
|
||||
border-top: 1px solid var(--alert-accent-color);
|
||||
}
|
||||
@@ -10,77 +10,213 @@
|
||||
INGROUP: Moko-Cassiopeia
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
PATH: ./templates/moko-cassiopeia/component.php
|
||||
VERSION: 03.05.00
|
||||
BRIEF: Minimal component-only template file for Moko-Cassiopeia
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Main template index file for Moko-Cassiopeia rendering site layout
|
||||
*/
|
||||
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
|
||||
/** @var Joomla\CMS\Document\HtmlDocument $this */
|
||||
|
||||
$app = Factory::getApplication();
|
||||
$wa = $this->getWebAssetManager();
|
||||
$app = Factory::getApplication();
|
||||
$input = $app->getInput();
|
||||
$document = $app->getDocument();
|
||||
$wa = $document->getWebAssetManager();
|
||||
|
||||
// Color Theme
|
||||
$paramsColorName = $this->params->get('colorName', 'colors_standard');
|
||||
$assetColorName = 'theme.' . $paramsColorName;
|
||||
$wa->registerAndUseStyle($assetColorName, 'media/templates/site/moko-cassiopeia/css/global/' . $paramsColorName . '.css');
|
||||
// Template params
|
||||
$params_LightColorName = (string) $this->params->get('colorLightName', 'colors_standard'); // colors_standard|colors_alternative|colors_custom
|
||||
|
||||
// Use a font scheme if set in the template style options
|
||||
$paramsFontScheme = $this->params->get('useFontScheme', false);
|
||||
$fontStyles = '';
|
||||
$params_DarkColorName = (string) $this->params->get('colorDarkName', 'colors_standard'); // colors_standard|colors_alternative|colors_custom
|
||||
|
||||
if ($paramsFontScheme) {
|
||||
if (stripos($paramsFontScheme, 'https://') === 0) {
|
||||
$params_googletagmanager = $this->params->get('googletagmanager', false);
|
||||
$params_googletagmanagerid = $this->params->get('googletagmanagerid', null);
|
||||
$params_googleanalytics = $this->params->get('googleanalytics', false);
|
||||
$params_googleanalyticsid = $this->params->get('googleanalyticsid', null);
|
||||
$params_custom_head_start = $this->params->get('custom_head_start', null);
|
||||
$params_custom_head_end = $this->params->get('custom_head_end', null);
|
||||
$params_developmentmode = $this->params->get('developmentmode', false);
|
||||
|
||||
// Bootstrap behaviors (assets handled via WAM)
|
||||
HTMLHelper::_('bootstrap.framework');
|
||||
HTMLHelper::_('bootstrap.alert');
|
||||
HTMLHelper::_('bootstrap.button');
|
||||
HTMLHelper::_('bootstrap.carousel');
|
||||
HTMLHelper::_('bootstrap.collapse');
|
||||
HTMLHelper::_('bootstrap.dropdown');
|
||||
HTMLHelper::_('bootstrap.modal');
|
||||
HTMLHelper::_('bootstrap.offcanvas');
|
||||
HTMLHelper::_('bootstrap.popover');
|
||||
HTMLHelper::_('bootstrap.scrollspy');
|
||||
HTMLHelper::_('bootstrap.tab');
|
||||
HTMLHelper::_('bootstrap.tooltip');
|
||||
HTMLHelper::_('bootstrap.toast');
|
||||
|
||||
// Detecting Active Variables
|
||||
$option = $input->getCmd('option', '');
|
||||
$view = $input->getCmd('view', '');
|
||||
$layout = $input->getCmd('layout', '');
|
||||
$task = $input->getCmd('task', '');
|
||||
$itemid = $input->getCmd('Itemid', '');
|
||||
$sitenameR = $app->get('sitename'); // raw for title composition
|
||||
$sitename = htmlspecialchars($sitenameR, ENT_QUOTES, 'UTF-8');
|
||||
$menu = $app->getMenu()->getActive();
|
||||
$pageclass = $menu !== null ? $menu->getParams()->get('pageclass_sfx', '') : '';
|
||||
|
||||
// Respect “Site Name in Page Titles” (0:none, 1:before, 2:after)
|
||||
$mode = (int) $app->get('sitename_pagetitles', 0);
|
||||
$pageTitle = trim($this->getTitle());
|
||||
$final = $pageTitle !== ''
|
||||
? ($mode === 1 ? $sitenameR . ' - ' . $pageTitle
|
||||
: ($mode === 2 ? $pageTitle . ' - ' . $sitenameR : $pageTitle))
|
||||
: $sitenameR;
|
||||
$this->setTitle($final);
|
||||
|
||||
// Template/Media path
|
||||
$templatePath = 'media/templates/site/moko-cassiopeia';
|
||||
|
||||
// Core template CSS
|
||||
$wa->useStyle('template.base'); // css/template.css
|
||||
$wa->useStyle('template.vendor.social-media-demo'); // css/user.css
|
||||
|
||||
// Optional vendor CSS
|
||||
$wa->useStyle('vendor.bootstrap-toc');
|
||||
|
||||
// Optional demo/showcase CSS (available for use, not loaded by default)
|
||||
// To use: Add 'template.global.social-media-demo' to your article/module
|
||||
// $wa->useStyle('template.global.social-media-demo');
|
||||
|
||||
// Color theme (light + optional dark)
|
||||
$colorLightKey = strtolower(preg_replace('/[^a-z0-9_.-]/i', '', $params_LightColorName));
|
||||
$colorDarkKey = strtolower(preg_replace('/[^a-z0-9_.-]/i', '', $params_DarkColorName));
|
||||
$lightKey = 'template.light.' . $colorLightKey;
|
||||
$darkKey = 'template.dark.' . $colorDarkKey;
|
||||
try {
|
||||
$wa->useStyle('template.light.colors_standard');
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.light.colors_standard', $templatePath . '/css/global/light/colors_standard.css');
|
||||
}
|
||||
try {
|
||||
$wa->useStyle('template.dark.colors_standard');
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.dark.colors_standard', $templatePath . '/css/global/dark/colors_standard.css');
|
||||
}
|
||||
try {
|
||||
$wa->useStyle($lightKey);
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.light.dynamic', $templatePath . '/css/global/light/' . $colorLightKey . '.css');
|
||||
}
|
||||
try {
|
||||
$wa->useStyle($darkKey);
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.dark.dynamic', $templatePath . '/css/global/dark/' . $colorDarkKey . '.css');
|
||||
}
|
||||
|
||||
// Scripts
|
||||
$wa->useScript('template.js');
|
||||
$wa->useScript('theme-init.js');
|
||||
$wa->useScript('vendor.bootstrap-toc.js');
|
||||
|
||||
/**
|
||||
* VirtueMart detection:
|
||||
* - Component must exist and be enabled
|
||||
*/
|
||||
$isVirtueMartActive = ComponentHelper::isEnabled('com_virtuemart', true);
|
||||
|
||||
if ($isVirtueMartActive) {
|
||||
/**
|
||||
* Load a VirtueMart-specific stylesheet defined in your template manifest.
|
||||
* This assumes you defined an asset named "template.virtuemart".
|
||||
*/
|
||||
$wa->useStyle('vendor.vm');
|
||||
}
|
||||
|
||||
// Font scheme (external or local) + CSS custom properties
|
||||
$params_FontScheme = $this->params->get('useFontScheme', false);
|
||||
$fontStyles = '';
|
||||
|
||||
if ($params_FontScheme) {
|
||||
if (stripos($params_FontScheme, 'https://') === 0) {
|
||||
$this->getPreloadManager()->preconnect('https://fonts.googleapis.com/', ['crossorigin' => 'anonymous']);
|
||||
$this->getPreloadManager()->preconnect('https://fonts.gstatic.com/', ['crossorigin' => 'anonymous']);
|
||||
$this->getPreloadManager()->preload($paramsFontScheme, ['as' => 'style', 'crossorigin' => 'anonymous']);
|
||||
$wa->registerAndUseStyle('fontscheme.current', $paramsFontScheme, [], ['media' => 'print', 'rel' => 'lazy-stylesheet', 'onload' => 'this.media=\'all\'', 'crossorigin' => 'anonymous']);
|
||||
$this->getPreloadManager()->preload($params_FontScheme, ['as' => 'style', 'crossorigin' => 'anonymous']);
|
||||
$wa->registerAndUseStyle('fontscheme.current', $params_FontScheme, [], [
|
||||
'media' => 'print',
|
||||
'rel' => 'lazy-stylesheet',
|
||||
'onload' => 'this.media=\'all\'',
|
||||
'crossorigin' => 'anonymous'
|
||||
]);
|
||||
|
||||
if (preg_match_all('/family=([^?:]*):/i', $paramsFontScheme, $matches) > 0) {
|
||||
$fontStyles = '--font-family-body: "' . str_replace('+', ' ', $matches[1][0]) . '", sans-serif;
|
||||
--font-family-headings: "' . str_replace('+', ' ', isset($matches[1][1]) ? $matches[1][1] : $matches[1][0]) . '", sans-serif;
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-headings: 700;';
|
||||
if (preg_match_all('/family=([^?:]*):/i', $params_FontScheme, $matches) > 0) {
|
||||
$fontStyles = '--font-family-body: "' . str_replace('+', ' ', $matches[1][0]) . '", sans-serif;' . "\n";
|
||||
$fontStyles .= '--font-family-headings: "' . str_replace('+', ' ', isset($matches[1][1]) ? $matches[1][1] : $matches[1][0]) . '", sans-serif;' . "\n";
|
||||
$fontStyles .= '--font-weight-normal: 400;' . "\n";
|
||||
$fontStyles .= '--font-weight-headings: 700;';
|
||||
}
|
||||
} else {
|
||||
$wa->registerAndUseStyle('fontscheme.current', $paramsFontScheme, ['version' => 'auto'], ['media' => 'print', 'rel' => 'lazy-stylesheet', 'onload' => 'this.media=\'all\'']);
|
||||
$this->getPreloadManager()->preload($wa->getAsset('style', 'fontscheme.current')->getUri() . '?' . $this->getMediaVersion(), ['as' => 'style']);
|
||||
$wa->registerAndUseStyle('fontscheme.current', $params_FontScheme, ['version' => 'auto'], [
|
||||
'media' => 'print',
|
||||
'rel' => 'lazy-stylesheet',
|
||||
'onload' => 'this.media=\'all\''
|
||||
]);
|
||||
$this->getPreloadManager()->preload(
|
||||
$wa->getAsset('style', 'fontscheme.current')->getUri() . '?' . $this->getMediaVersion(),
|
||||
['as' => 'style']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable assets
|
||||
$wa->usePreset('template.moko-cassiopeia.' . ($this->direction === 'rtl' ? 'rtl' : 'ltr'))
|
||||
->useStyle('template.active.language')
|
||||
->useStyle('template.user')
|
||||
->useScript('template.user')
|
||||
->addInlineStyle(":root {
|
||||
--hue: 214;
|
||||
--template-bg-light: #f0f4fb;
|
||||
--template-text-dark: #495057;
|
||||
--template-text-light: #ffffff;
|
||||
--template-link-color: #2a69b8;
|
||||
--template-special-color: #001B4C;
|
||||
$fontStyles
|
||||
}");
|
||||
// Meta
|
||||
$this->setMetaData('viewport', 'width=device-width, initial-scale=1');
|
||||
|
||||
if ($this->params->get('faKitCode')) {
|
||||
$faKit = "https://kit.fontawesome.com/" . $this->params->get('faKitCode') . ".js";
|
||||
HTMLHelper::_('script', $faKit, ['crossorigin' => 'anonymous']);
|
||||
} else {
|
||||
try {
|
||||
if($params_developmentmode){
|
||||
$wa->useStyle('vendor.fa7free.all');
|
||||
$wa->useStyle('vendor.fa7free.brands');
|
||||
$wa->useStyle('vendor.fa7free.fontawesome');
|
||||
$wa->useStyle('vendor.fa7free.regular');
|
||||
$wa->useStyle('vendor.fa7free.solid');
|
||||
} else {
|
||||
$wa->useStyle('vendor.fa7free.all.min');
|
||||
$wa->useStyle('vendor.fa7free.brands.min');
|
||||
$wa->useStyle('vendor.fa7free.fontawesome.min');
|
||||
$wa->useStyle('vendor.fa7free.regular.min');
|
||||
$wa->useStyle('vendor.fa7free.solid.min');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
if($params_developmentmode){
|
||||
$wa->registerAndUseStyle('vendor.fa7free.all.dynamic', $templatePath . '/vendor/fa7free/css/all.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.brands.dynamic', $templatePath . '/vendor/fa7free/css/brands.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.fontawesome.dynamic', $templatePath . '/vendor/fa7free/css/fontawesome.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.regular.dynamic', $templatePath . '/vendor/fa7free/css/regular.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.solid.dynamic', $templatePath . '/vendor/fa7free/css/solid.css');
|
||||
} else {
|
||||
$wa->registerAndUseStyle('vendor.fa7free.all.min.dynamic', $templatePath . '/vendor/fa7free/css/all.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.brands.min.dynamic', $templatePath . '/vendor/fa7free/css/brands.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.fontawesome.min.dynamic', $templatePath . '/vendor/fa7free/css/fontawesome.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.regular.min.dynamic', $templatePath . '/vendor/fa7free/css/regular.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.solid.min.dynamic', $templatePath . '/vendor/fa7free/css/solid.min.css');
|
||||
}
|
||||
|
||||
// Override 'template.active' asset to set correct ltr/rtl dependency
|
||||
$wa->registerStyle('template.active', '', [], [], ['template.moko-cassiopeia.' . ($this->direction === 'rtl' ? 'rtl' : 'ltr')]);
|
||||
}
|
||||
}
|
||||
$params_leftIcon = htmlspecialchars($this->params->get('drawerLeftIcon', 'fa-solid fa-chevron-left'), ENT_COMPAT, 'UTF-8');
|
||||
$params_rightIcon = htmlspecialchars($this->params->get('drawerRightIcon', 'fa-solid fa-chevron-right'), ENT_COMPAT, 'UTF-8');
|
||||
|
||||
// Browsers support SVG favicons
|
||||
$this->addHeadLink(HTMLHelper::_('image', 'joomla-favicon.svg', '', [], true, 1), 'icon', 'rel', ['type' => 'image/svg+xml']);
|
||||
$this->addHeadLink(HTMLHelper::_('image', 'favicon.ico', '', [], true, 1), 'alternate icon', 'rel', ['type' => 'image/vnd.microsoft.icon']);
|
||||
$this->addHeadLink(HTMLHelper::_('image', 'joomla-favicon-pinned.svg', '', [], true, 1), 'mask-icon', 'rel', ['color' => '#000']);
|
||||
|
||||
// Defer font awesome
|
||||
$wa->getAsset('style', 'fontawesome')->setAttribute('rel', 'lazy-stylesheet');
|
||||
$wa->useStyle('template.user'); // css/user.css
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<html class="component" lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<head>
|
||||
<jdoc:include type="metas" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
PATH: ./templates/moko-cassiopeia/custom.php
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Custom entry template file for Moko-Cassiopeia with user-defined overrides
|
||||
*/
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
PATH: ./templates/moko-cassiopeia/error.php
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Error page template file for Moko-Cassiopeia
|
||||
*/
|
||||
|
||||
@@ -26,72 +26,154 @@ $app = Factory::getApplication();
|
||||
$params = $this->params;
|
||||
$wa = $this->getWebAssetManager();
|
||||
|
||||
// Template params
|
||||
$params_LightColorName = (string) $params->get('colorLightName', 'colors_standard'); // colors_standard|colors_alternative|colors_custom
|
||||
|
||||
$params_DarkColorName = (string) $params->get('colorDarkName', 'colors_standard'); // colors_standard|colors_alternative|colors_custom
|
||||
|
||||
$params_googletagmanager = $params->get('googletagmanager', false);
|
||||
$params_googletagmanagerid = $params->get('googletagmanagerid', '');
|
||||
$params_googleanalytics = $params->get('googleanalytics', false);
|
||||
$params_googleanalyticsid = $params->get('googleanalyticsid', '');
|
||||
$params_custom_head_start = $params->get('custom_head_start', '');
|
||||
$params_custom_head_end = $params->get('custom_head_end', '');
|
||||
$params_developmentmode = $params->get('developmentmode', false);
|
||||
|
||||
// Bootstrap behaviors (assets handled via WAM)
|
||||
HTMLHelper::_('bootstrap.framework');
|
||||
HTMLHelper::_('bootstrap.loadCss', true);
|
||||
HTMLHelper::_('bootstrap.alert');
|
||||
HTMLHelper::_('bootstrap.button');
|
||||
HTMLHelper::_('bootstrap.carousel');
|
||||
HTMLHelper::_('bootstrap.collapse');
|
||||
HTMLHelper::_('bootstrap.dropdown');
|
||||
HTMLHelper::_('bootstrap.modal');
|
||||
HTMLHelper::_('bootstrap.offcanvas');
|
||||
HTMLHelper::_('bootstrap.popover');
|
||||
HTMLHelper::_('bootstrap.scrollspy');
|
||||
HTMLHelper::_('bootstrap.tab');
|
||||
HTMLHelper::_('bootstrap.tooltip');
|
||||
HTMLHelper::_('bootstrap.toast');
|
||||
|
||||
// ------------------ Params ------------------
|
||||
$colorLight = (string) $params->get('colorLightName', 'colors_standard');
|
||||
$colorDark = (string) $params->get('colorDarkName', 'colors_standard');
|
||||
$themeFab = (int) $params->get('theme_fab_enabled', 1);
|
||||
$fABodyPos = (string) $params->get('theme_fab_pos', 'br');
|
||||
$gtmEnabled = (int) $params->get('googletagmanager', 0);
|
||||
$gtmId = (string) $params->get('googletagmanagerid', '');
|
||||
$fa6KitCode = (string) $params->get('fA6KitCode', '');
|
||||
$stickyHeader = (bool) $params->get('stickyHeader', 0);
|
||||
$brandEnabled = (int) $params->get('brand', 1);
|
||||
$siteDescription = (string) $params->get('siteDescription', '');
|
||||
|
||||
// Drawer icon params (escaped)
|
||||
$params_leftIcon = htmlspecialchars($params->get('drawerLeftIcon', 'fa-solid fa-chevron-right'), ENT_QUOTES, 'UTF-8');
|
||||
$params_rightIcon = htmlspecialchars($params->get('drawerRightIcon', 'fa-solid fa-chevron-left'), ENT_QUOTES, 'UTF-8');
|
||||
$params_leftIcon = htmlspecialchars($params->get('drawerLeftIcon', 'fa-solid fa-chevron-left'), ENT_QUOTES, 'UTF-8');
|
||||
$params_rightIcon = htmlspecialchars($params->get('drawerRightIcon', 'fa-solid fa-chevron-right'), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// ------------------ Styles ------------------
|
||||
$wa->useStyle('template.base');
|
||||
$wa->useStyle('template.user');
|
||||
// Template/Media path
|
||||
$templatePath = 'media/templates/site/moko-cassiopeia';
|
||||
|
||||
// Light/Dark variable sheets (load before consumers)
|
||||
if ($wa->assetExists('style', 'template.light.' . $colorLight)) {
|
||||
$wa->useStyle('template.light.' . $colorLight);
|
||||
// ===========================
|
||||
// Web Asset Manager (WAM) — matches your joomla.asset.json
|
||||
// ===========================
|
||||
|
||||
// Core template CSS
|
||||
$wa->useStyle('template.global.base'); // css/template.css
|
||||
$wa->useStyle('template.global.social-media-demo'); // css/global/social-media-demo.css
|
||||
|
||||
// Optional vendor CSS
|
||||
$wa->useStyle('vendor.bootstrap-toc');
|
||||
|
||||
// Color theme (light + optional dark)
|
||||
$colorLightKey = strtolower(preg_replace('/[^a-z0-9_.-]/i', '', $params_LightColorName));
|
||||
$colorDarkKey = strtolower(preg_replace('/[^a-z0-9_.-]/i', '', $params_DarkColorName));
|
||||
$lightKey = 'template.light.' . $colorLightKey;
|
||||
$darkKey = 'template.dark.' . $colorDarkKey;
|
||||
try {
|
||||
$wa->useStyle('template.light.colors_standard');
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.light.colors_standard', $templatePath . '/css/global/light/colors_standard.css');
|
||||
}
|
||||
if ($wa->assetExists('style', 'template.dark.' . $colorDark)) {
|
||||
$wa->useStyle('template.dark.' . $colorDark);
|
||||
try {
|
||||
$wa->useStyle('template.dark.colors_standard');
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.dark.colors_standard', $templatePath . '/css/global/dark/colors_standard.css');
|
||||
}
|
||||
try {
|
||||
$wa->useStyle($lightKey);
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.light.dynamic', $templatePath . '/css/global/light/' . $colorLightKey . '.css');
|
||||
}
|
||||
try {
|
||||
$wa->useStyle($darkKey);
|
||||
} catch (\Throwable $e) {
|
||||
$wa->registerAndUseStyle('template.dark.dynamic', $templatePath . '/css/global/dark/' . $colorDarkKey . '.css');
|
||||
}
|
||||
|
||||
// ------------------ Scripts ------------------
|
||||
// Scripts
|
||||
$wa->useScript('template.js');
|
||||
$wa->useScript('theme-init.js');
|
||||
if ($themeFab === 1) {
|
||||
$wa->useScript('darkmode-toggle.js');
|
||||
}
|
||||
if ($gtmEnabled === 1) {
|
||||
$wa->useScript('gtm.js');
|
||||
$wa->useScript('darkmode-toggle.js');
|
||||
$wa->useScript('vendor.bootstrap-toc.js');
|
||||
|
||||
// Meta
|
||||
$this->setMetaData('viewport', 'width=device-width, initial-scale=1');
|
||||
|
||||
if ($this->params->get('faKitCode')) {
|
||||
$faKit = "https://kit.fontawesome.com/" . $this->params->get('faKitCode') . ".js";
|
||||
HTMLHelper::_('script', $faKit, ['crossorigin' => 'anonymous']);
|
||||
} else {
|
||||
try {
|
||||
if ($params_developmentmode){
|
||||
$wa->useStyle('vendor.fa7free.all');
|
||||
$wa->useStyle('vendor.fa7free.brands');
|
||||
$wa->useStyle('vendor.fa7free.fontawesome');
|
||||
$wa->useStyle('vendor.fa7free.regular');
|
||||
$wa->useStyle('vendor.fa7free.solid');
|
||||
} else {
|
||||
$wa->useStyle('vendor.fa7free.all.min');
|
||||
$wa->useStyle('vendor.fa7free.brands.min');
|
||||
$wa->useStyle('vendor.fa7free.fontawesome.min');
|
||||
$wa->useStyle('vendor.fa7free.regular.min');
|
||||
$wa->useStyle('vendor.fa7free.solid.min');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
if ($params_developmentmode){
|
||||
$wa->registerAndUseStyle('vendor.fa7free.all.dynamic', $templatePath . '/vendor/fa7free/css/all.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.brands.dynamic', $templatePath . '/vendor/fa7free/css/brands.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.fontawesome.dynamic', $templatePath . '/vendor/fa7free/css/fontawesome.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.regular.dynamic', $templatePath . '/vendor/fa7free/css/regular.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.solid.dynamic', $templatePath . '/vendor/fa7free/css/solid.css');
|
||||
} else {
|
||||
$wa->registerAndUseStyle('vendor.fa7free.all.min.dynamic', $templatePath . '/vendor/fa7free/css/all.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.brands.min.dynamic', $templatePath . '/vendor/fa7free/css/brands.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.fontawesome.min.dynamic', $templatePath . '/vendor/fa7free/css/fontawesome.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.regular.min.dynamic', $templatePath . '/vendor/fa7free/css/regular.min.css');
|
||||
$wa->registerAndUseStyle('vendor.fa7free.solid.min.dynamic', $templatePath . '/vendor/fa7free/css/solid.min.css');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Optional Font Awesome 6 Kit (preferred) or FA5 fallback
|
||||
if (!empty($fa6KitCode)) {
|
||||
HTMLHelper::_('script', 'https://kit.fontawesome.com/' . rawurlencode($fa6KitCode) . '.js', [
|
||||
'crossorigin' => 'anonymous'
|
||||
]);
|
||||
} else {
|
||||
HTMLHelper::_('stylesheet', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', ['version' => 'auto'], [
|
||||
'crossorigin' => 'anonymous',
|
||||
'referrerpolicy' => 'no-referrer',
|
||||
]);
|
||||
}
|
||||
$wa->useStyle('template.user'); // css/user.css
|
||||
|
||||
// ------------------ Context (logo, bootstrap needs) ------------------
|
||||
$sitename = htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// Build logo/title
|
||||
if ($params->get('logoFile')) {
|
||||
$logo = HTMLHelper::_(
|
||||
// -------------------------------------
|
||||
// Brand: logo from params OR siteTitle
|
||||
// -------------------------------------
|
||||
$brandHtml = '';
|
||||
$logoFile = (string) $this->params->get('logoFile');
|
||||
|
||||
if ($logoFile !== '') {
|
||||
$brandHtml = HTMLHelper::_(
|
||||
'image',
|
||||
Uri::root(false) . htmlspecialchars($params->get('logoFile'), ENT_QUOTES),
|
||||
Uri::root(false) . htmlspecialchars($logoFile, ENT_QUOTES, 'UTF-8'),
|
||||
$sitename,
|
||||
['loading' => 'eager', 'decoding' => 'async'],
|
||||
['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'],
|
||||
false,
|
||||
0
|
||||
);
|
||||
} elseif ($params->get('siteTitle')) {
|
||||
$logo = '<span title="' . $sitename . '">' . htmlspecialchars($params->get('siteTitle'), ENT_COMPAT, 'UTF-8') . '</span>';
|
||||
} elseif ($this->params->get('siteTitle')) {
|
||||
$brandHtml = '<span class="site-title" title="' . $sitename . '">'
|
||||
. htmlspecialchars($this->params->get('siteTitle'), ENT_COMPAT, 'UTF-8')
|
||||
. '</span>';
|
||||
} else {
|
||||
$logo = HTMLHelper::_('image', 'full_logo.png', $sitename, ['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'], true, 0);
|
||||
// Fallback to a bundled image (relative to media paths)
|
||||
$brandHtml = HTMLHelper::_('image', 'full_logo.png', $sitename, ['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'], true, 0);
|
||||
}
|
||||
|
||||
// ------------------ Error details ------------------
|
||||
@@ -103,23 +185,105 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#ffffff" id="meta-theme-color" />
|
||||
<?php if ($params_custom_head_start !== '') : ?><?php echo $params_custom_head_start; ?><?php endif; ?>
|
||||
<jdoc:include type="head" />
|
||||
|
||||
<script>
|
||||
// Early theme application to avoid FOUC
|
||||
(function () {
|
||||
try {
|
||||
var stored = localStorage.getItem('theme');
|
||||
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
var theme = stored ? stored : (prefersDark ? 'dark' : 'light');
|
||||
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Facebook in-app browser warning banner
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
var ua = navigator.userAgent || navigator.vendor || window.opera;
|
||||
var isFacebookBrowser = ua.indexOf('FBAN') > -1 || ua.indexOf('FBAV') > -1;
|
||||
if (isFacebookBrowser) {
|
||||
var warning = document.createElement('div');
|
||||
warning.textContent = '⚠️ KNOWN ISSUE: Images do not load in Facebook Web browser. Please open in external browser for full experience.';
|
||||
warning.style.position = 'fixed';
|
||||
warning.style.top = '0';
|
||||
warning.style.left = '0';
|
||||
warning.style.right = '0';
|
||||
warning.style.zIndex = '10000';
|
||||
warning.style.backgroundColor = '#007bff';
|
||||
warning.style.color = '#fff';
|
||||
warning.style.padding = '15px';
|
||||
warning.style.textAlign = 'center';
|
||||
warning.style.fontWeight = 'bold';
|
||||
warning.style.fontSize = '16px';
|
||||
warning.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
|
||||
document.body.appendChild(warning);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php if ($params_custom_head_end !== '') : ?><?php echo $params_custom_head_end; ?><?php endif; ?>
|
||||
</head>
|
||||
<body data-theme-fab-pos="<?php echo htmlspecialchars($fABodyPos, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<?php if ($gtmEnabled === 1 && !empty($gtmId)) : ?>
|
||||
<body data-bs-spy="scroll" data-bs-target="#toc" class="site error-page<?php
|
||||
echo ($this->direction == 'rtl' ? ' rtl' : '');
|
||||
?>">
|
||||
<?php if (!empty($params_googletagmanager) && !empty($params_googletagmanagerid)) : ?>
|
||||
<!-- Google Tag Manager -->
|
||||
<script>
|
||||
(function(w,d,s,l,i){
|
||||
w[l]=w[l]||[];
|
||||
w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});
|
||||
var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),
|
||||
dl=l!='dataLayer'?'&l='+l:'';
|
||||
j.async=true;
|
||||
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
|
||||
f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer',<?php echo json_encode($params_googletagmanagerid, JSON_HEX_TAG | JSON_HEX_AMP); ?>);
|
||||
</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript>
|
||||
<iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo htmlspecialchars($gtmId, ENT_QUOTES, 'UTF-8'); ?>"
|
||||
<iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo htmlspecialchars($params_googletagmanagerid, ENT_QUOTES, 'UTF-8'); ?>"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe>
|
||||
</noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ========== DUPLICATED HEADER FROM INDEX ========== -->
|
||||
<header class="header container-header full-width<?php echo $stickyHeader ? ' position-sticky sticky-top' : ''; ?>">
|
||||
<?php if (!empty($params_googleanalytics) && !empty($params_googleanalyticsid)) : ?>
|
||||
<!-- Google Analytics (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=<?php echo htmlspecialchars($params_googleanalyticsid, ENT_QUOTES, 'UTF-8'); ?>"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('consent', 'default', {
|
||||
'ad_storage': 'denied',
|
||||
'analytics_storage': 'granted',
|
||||
'ad_user_data': 'denied',
|
||||
'ad_personalization': 'denied'
|
||||
});
|
||||
(function(id){
|
||||
if (/^G-/.test(id)) {
|
||||
gtag('config', id, { 'anonymize_ip': true });
|
||||
} else if (/^UA-/.test(id)) {
|
||||
gtag('config', id, { 'anonymize_ip': true });
|
||||
console.warn('Using a UA- ID. Universal Analytics is sunset; consider migrating to GA4.');
|
||||
} else {
|
||||
console.warn('Unrecognized Google Analytics ID format:', id);
|
||||
}
|
||||
})(<?php echo json_encode($params_googleanalyticsid, JSON_HEX_TAG | JSON_HEX_AMP); ?>);
|
||||
</script>
|
||||
<!-- End Google Analytics -->
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ========== HEADER FROM INDEX ========== -->
|
||||
<header class="header container-header full-width<?php echo $stickyHeader ? ' position-sticky sticky-top' : ''; ?>" role="banner">
|
||||
|
||||
<?php if ($this->countModules('topbar')) : ?>
|
||||
<div class="container-topbar">
|
||||
<jdoc:include type="modules" name="topbar" style="none" />
|
||||
@@ -133,14 +297,16 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($brandEnabled) : ?>
|
||||
<?php if ($this->params->get('brand', 1)) : ?>
|
||||
<div class="grid-child">
|
||||
<div class="navbar-brand">
|
||||
<a class="brand-logo" href="<?php echo $this->baseurl; ?>/">
|
||||
<?php echo $logo; ?>
|
||||
<?php echo $brandHtml; ?>
|
||||
</a>
|
||||
<?php if (!empty($siteDescription)) : ?>
|
||||
<div class="site-description"><?php echo htmlspecialchars($siteDescription); ?></div>
|
||||
<?php if ($this->params->get('siteDescription')) : ?>
|
||||
<div class="site-description">
|
||||
<?php echo htmlspecialchars($this->params->get('siteDescription'), ENT_QUOTES, 'UTF-8'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,10 +319,33 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Drawer Toggle Buttons -->
|
||||
<?php if ($this->countModules('drawer-left')) : ?>
|
||||
<button class="drawer-toggle-left btn btn-outline-secondary me-2"
|
||||
type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#drawer-left"
|
||||
aria-controls="drawer-left">
|
||||
<span class="<?php echo $params_leftIcon; ?>"></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($this->countModules('drawer-right')) : ?>
|
||||
<button class="drawer-toggle-right btn btn-outline-secondary"
|
||||
type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#drawer-right"
|
||||
aria-controls="drawer-right">
|
||||
<span class="<?php echo $params_rightIcon; ?>"></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($this->countModules('menu', true) || $this->countModules('search', true)) : ?>
|
||||
<div class="grid-child container-nav">
|
||||
<?php if ($this->countModules('menu', true)) : ?>
|
||||
<jdoc:include type="modules" name="menu" style="none" />
|
||||
<nav role="navigation" aria-label="Primary">
|
||||
<jdoc:include type="modules" name="menu" style="none" />
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
<?php if ($this->countModules('search', true)) : ?>
|
||||
<div class="container-search">
|
||||
@@ -166,7 +355,7 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
<!-- ========== END DUPLICATED HEADER ========== -->
|
||||
<!-- ========== END HEADER ========== -->
|
||||
|
||||
<main class="container my-4">
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
@@ -186,11 +375,11 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a class="btn btn-primary" href="<?php echo htmlspecialchars(Uri::base(), ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<i class="fas fa-home me-1" aria-hidden="true"></i>
|
||||
<i class="fa-solid fa-home me-1" aria-hidden="true"></i>
|
||||
<?php echo Text::_('JERROR_LAYOUT_HOME_PAGE'); ?>
|
||||
</a>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="history.back();">
|
||||
<i class="fas fa-arrow-left me-1" aria-hidden="true"></i>
|
||||
<i class="fa-solid fa-arrow-left me-1" aria-hidden="true"></i>
|
||||
<?php echo Text::_('JPREV'); ?>
|
||||
</button>
|
||||
</div>
|
||||
@@ -245,7 +434,7 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
<footer class="container-footer footer full-width py-4">
|
||||
<footer class="container-footer footer full-width">
|
||||
<?php if ($this->countModules('footer-menu', true)) : ?>
|
||||
<div class="grid-child footer-menu">
|
||||
<jdoc:include type="modules" name="footer-menu" />
|
||||
@@ -258,6 +447,37 @@ $debugOn = defined('JDEBUG') && JDEBUG;
|
||||
<?php endif; ?>
|
||||
</footer>
|
||||
|
||||
<?php if ($this->params->get('backTop') == 1) : ?>
|
||||
<a href="#top" id="back-top" class="back-to-top-link" aria-label="<?php echo Text::_('TPL_MOKO-CASSIOPEIA_BACKTOTOP'); ?>">
|
||||
<span class="icon-arrow-up icon-fw" aria-hidden="true"></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($this->countModules('drawer-left', true)) : ?>
|
||||
<!-- Left Offcanvas Drawer -->
|
||||
<aside class="offcanvas offcanvas-start" tabindex="-1" id="drawer-left">
|
||||
<div class="offcanvas-header">
|
||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="<?php echo Text::_('JLIB_HTML_BEHAVIOR_CLOSE'); ?>"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<jdoc:include type="modules" name="drawer-left" style="none" />
|
||||
</div>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($this->countModules('drawer-right', true)) : ?>
|
||||
<!-- Right Offcanvas Drawer -->
|
||||
<aside class="offcanvas offcanvas-end" tabindex="-1" id="drawer-right">
|
||||
<div class="offcanvas-header">
|
||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="<?php echo Text::_('JLIB_HTML_BEHAVIOR_CLOSE'); ?>"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<jdoc:include type="modules" name="drawer-right" style="none" />
|
||||
</div>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
<jdoc:include type="modules" name="debug" style="none" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
PATH: ./templates/moko-cassiopeia/html/com_content/article/toc-left.php
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Template override for Joomla articles with Table of Contents aligned left
|
||||
*/
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
INGROUP: Moko-Cassiopeia
|
||||
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
|
||||
PATH: ./templates/moko-cassiopeia/html/com_content/article/toc-right.php
|
||||
VERSION: 03.05.00
|
||||
VERSION: 03.06.00
|
||||
BRIEF: Template override for Joomla articles with Table of Contents aligned right
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var MPFInput $input
|
||||
* @var MPFConfig $config
|
||||
* @var int $Itemid
|
||||
* @var int $categoryId
|
||||
* @var OSMembershipHelperBootstrap $bootstrapHelper
|
||||
*/
|
||||
|
||||
$rootUri = Uri::root(true);
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
if (!isset($categoryId))
|
||||
{
|
||||
$categoryId = 0;
|
||||
}
|
||||
|
||||
$rowFluidClass = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$span7Class = $bootstrapHelper->getClassMapping('span7');
|
||||
$span5class = $bootstrapHelper->getClassMapping('span5');
|
||||
$imgClass = $bootstrapHelper->getClassMapping('img-polaroid');
|
||||
$btnClass = $bootstrapHelper->getClassMapping('btn');
|
||||
$btnPrimaryClass = $bootstrapHelper->getClassMapping('btn btn-primary');
|
||||
$clearfixClass = $bootstrapHelper->getClassMapping('clearfix');
|
||||
|
||||
$defaultItemId = $Itemid;
|
||||
|
||||
for ($i = 0 , $n = count($items) ; $i < $n ; $i++)
|
||||
{
|
||||
$item = $items[$i];
|
||||
$Itemid = OSMembershipHelperRoute::getPlanMenuId($item->id, $item->category_id, $defaultItemId);
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = $rootUri . '/media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
if ($item->category_id)
|
||||
{
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&catid=' . $item->category_id . '&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
}
|
||||
|
||||
if ($config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid));
|
||||
}
|
||||
|
||||
$symbol = $item->currency_symbol ?: $item->currency;
|
||||
?>
|
||||
<div class="osm-item-wrapper <?php echo $clearfixClass; ?>">
|
||||
<div class="osm-item-heading-box <?php echo $clearfixClass; ?>">
|
||||
<h3 class="osm-item-title">
|
||||
<a href="<?php echo $url; ?>" title="<?php echo $item->title; ?>">
|
||||
<?php echo $item->title; ?>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="osm-item-description <?php echo $clearfixClass; ?>">
|
||||
<div class="<?php echo $rowFluidClass; ?>">
|
||||
<div class="osm-description-details <?php echo $span7Class; ?>">
|
||||
<?php
|
||||
if ($item->thumb)
|
||||
{
|
||||
?>
|
||||
<img src="<?php echo $imgSrc; ?>" alt="<?php echo $item->title; ?>" class="osm-thumb-left <?php echo $imgClass; ?>"/>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($item->short_description)
|
||||
{
|
||||
echo $item->short_description;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $item->description;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="<?php echo $span5class; ?>">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/plan_information.php', ['item' => $item]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="osm-taskbar <?php echo $clearfixClass; ?>">
|
||||
<ul>
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if (count($actions))
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="<?php echo $btnPrimaryClass; ?>">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="<?php echo $btnPrimaryClass; ?>">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($config->hide_details_button))
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $url; ?>" class="<?php echo $btnClass; ?>">
|
||||
<?php echo Text::_('OSM_DETAILS'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var string $selector
|
||||
* @var string $title
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
Factory::getApplication()
|
||||
->getDocument()
|
||||
->getWebAssetManager()
|
||||
->useScript('core');
|
||||
|
||||
Text::script('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST');
|
||||
$message = "alert(Joomla.JText._('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST'));";
|
||||
?>
|
||||
<button type="button" data-toggle="modal" onclick="if (document.adminForm.boxchecked.value==0){<?php echo $message; ?>}else{jQuery( '#<?php echo $selector; ?>' ).modal('show'); return true;}" class="btn btn-small">
|
||||
<span class="icon-checkbox-partial" aria-hidden="true"></span>
|
||||
<?php echo $title; ?>
|
||||
</button>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2010 - 2022 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var string $selector
|
||||
* @var string $title
|
||||
*/
|
||||
?>
|
||||
<button type="button" data-toggle="modal" onclick="jQuery( '#<?php echo $selector; ?>' ).modal('show'); return true;" class="btn btn-small">
|
||||
<span class="icon-checkbox-partial" aria-hidden="true"></span>
|
||||
<?php echo $title; ?>
|
||||
</button>
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var MPFConfig $config
|
||||
* @var int $categoryId
|
||||
* @var int $Itemid
|
||||
*/
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$clearfixClass = $bootstrapHelper->getClassMapping('clearfix');
|
||||
|
||||
for ($i = 0 , $n = count($items) ; $i < $n ; $i++)
|
||||
{
|
||||
$item = $items[$i];
|
||||
$link = Route::_(OSMembershipHelperRoute::getCategoryRoute($item->id, $Itemid));
|
||||
?>
|
||||
<div class="osm-item-wrapper clearfix">
|
||||
<div class="osm-item-heading-box">
|
||||
<h3 class="osm-item-title">
|
||||
<a href="<?php echo $link; ?>" class="osm-item-title-link">
|
||||
<?php echo $item->title;?>
|
||||
</a>
|
||||
<span class="<?php echo $bootstrapHelper->getClassMapping('badge badge-info'); ?>"><?php echo $item->total_plans ;?> <?php echo $item->total_plans > 1 ? Text::_('OSM_PLANS') : Text::_('OSM_PLAN') ; ?></span>
|
||||
</h3>
|
||||
</div>
|
||||
<?php
|
||||
if($item->description)
|
||||
{
|
||||
?>
|
||||
<div class="osm-item-description <?php echo $clearfixClass; ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $item->description);?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var int $categoryId
|
||||
* @var MPFInput $input
|
||||
* @var MPFConfig $config
|
||||
* @var OSMembershipHelperBootstrap $bootstrapHelper
|
||||
* @var \Joomla\Registry\Registry $params
|
||||
* @var int $Itemid
|
||||
*/
|
||||
|
||||
Factory::getApplication()
|
||||
->getDocument()
|
||||
->getWebAssetManager()
|
||||
->useScript('core');
|
||||
|
||||
$rootUri = Uri::root(true);
|
||||
$minHeight = 130;
|
||||
|
||||
if (isset($params))
|
||||
{
|
||||
$minHeight = (int) $params->get('min_height', 130) ?: 130;
|
||||
}
|
||||
|
||||
OSMembershipHelperJquery::responsiveEqualHeight('.osm-item-description-text', $minHeight);
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
if (isset($input) && $input->getInt('number_columns'))
|
||||
{
|
||||
$numberColumns = $input->getInt('number_columns');
|
||||
}
|
||||
elseif (!empty($config->number_columns))
|
||||
{
|
||||
$numberColumns = $config->number_columns;
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberColumns = 3;
|
||||
}
|
||||
|
||||
if (!isset($categoryId))
|
||||
{
|
||||
$categoryId = 0;
|
||||
}
|
||||
|
||||
$span = intval(12 / $numberColumns);
|
||||
|
||||
$btnClass = $bootstrapHelper->getClassMapping('btn');
|
||||
$btnPrimaryClass = $bootstrapHelper->getClassMapping('btn btn-primary');
|
||||
$imgClass = $bootstrapHelper->getClassMapping('img-polaroid');
|
||||
$spanClass = $bootstrapHelper->getClassMapping('span' . $span);
|
||||
$rowFluidClearfixClass = $bootstrapHelper->getClassMapping('row-fluid clearfix');
|
||||
$clearFixClass = $bootstrapHelper->getClassMapping('clearfix');
|
||||
?>
|
||||
<div class="<?php echo $rowFluidClearfixClass; ?>">
|
||||
<?php
|
||||
$i = 0;
|
||||
$numberPlans = count($items);
|
||||
$defaultItemId = $Itemid;
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$i++;
|
||||
|
||||
$Itemid = OSMembershipHelperRoute::getPlanMenuId($item->id, $item->category_id, $defaultItemId);
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = $rootUri . '/media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&catid=' . $item->category_id . '&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
|
||||
if ($config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid));
|
||||
}
|
||||
?>
|
||||
<div class="osm-item-wrapper <?php echo $spanClass; ?>">
|
||||
<div class="osm-item-heading-box <?php echo $clearFixClass; ?>">
|
||||
<h2 class="osm-item-title">
|
||||
<a href="<?php echo $url; ?>" title="<?php echo $item->title; ?>">
|
||||
<?php echo $item->title; ?>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="osm-item-description <?php echo $clearFixClass; ?>">
|
||||
<?php
|
||||
if ($item->thumb)
|
||||
{
|
||||
?>
|
||||
<a href="<?php echo $url; ?>" title="<?php echo $item->title; ?>">
|
||||
<img src="<?php echo $imgSrc; ?>" class="osm-thumb-left <?php echo $imgClass; ?>" />
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!$item->short_description)
|
||||
{
|
||||
$item->short_description = $item->description;
|
||||
}
|
||||
?>
|
||||
<div class="osm-item-description-text"><?php echo $item->short_description; ?></div>
|
||||
<div class="osm-taskbar <?php echo $clearFixClass; ?>">
|
||||
<ul>
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if (count($actions))
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="<?php echo $btnPrimaryClass; ?>">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="<?php echo $btnPrimaryClass; ?>">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($config->hide_details_button))
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $url; ?>" class="<?php echo $btnClass; ?>">
|
||||
<?php echo Text::_('OSM_DETAILS'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($i % $numberColumns == 0 && $i < $numberPlans)
|
||||
{
|
||||
?>
|
||||
</div>
|
||||
<div class="<?php echo $rowFluidClearfixClass; ?>">
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@@ -1,231 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var int $categoryId
|
||||
* @var MPFInput $input
|
||||
* @var MPFConfig $config
|
||||
* @var OSMembershipHelperBootstrap $bootstrapHelper
|
||||
* @var \Joomla\Registry\Registry $params
|
||||
* @var int $Itemid
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
$rootUri = Uri::root(true);
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
if (!isset($categoryId))
|
||||
{
|
||||
$categoryId = 0;
|
||||
}
|
||||
|
||||
$rowFluidClass = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$imgClass = $bootstrapHelper->getClassMapping('img-polaroid');
|
||||
$btnClass = $bootstrapHelper->getClassMapping('btn');
|
||||
$btnPrimaryClass = $bootstrapHelper->getClassMapping('btn btn-primary');
|
||||
$clearfixClass = $bootstrapHelper->getClassMapping('clearfix');
|
||||
|
||||
$defaultItemId = $Itemid;
|
||||
|
||||
if (isset($params))
|
||||
{
|
||||
$showPlanInformation = $params->get('show_plan_information', 1);
|
||||
$planInformationPosition = $params->get('plan_information_position', 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$showPlanInformation = 1;
|
||||
$planInformationPosition = 0;
|
||||
}
|
||||
|
||||
if ($showPlanInformation && $planInformationPosition == 0)
|
||||
{
|
||||
$leftClass = $bootstrapHelper->getClassMapping('span7');
|
||||
$rightClass = $bootstrapHelper->getClassMapping('span5');
|
||||
}
|
||||
else
|
||||
{
|
||||
$leftClass = $bootstrapHelper->getClassMapping('clearfix');
|
||||
$rightClass = $bootstrapHelper->getClassMapping('clearfix');
|
||||
}
|
||||
|
||||
for ($i = 0 , $n = count($items) ; $i < $n ; $i++)
|
||||
{
|
||||
$item = $items[$i];
|
||||
$Itemid = OSMembershipHelperRoute::getPlanMenuId($item->id, $item->category_id, $defaultItemId);
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = $rootUri . '/media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
if ($item->category_id)
|
||||
{
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&catid=' . $item->category_id . '&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
}
|
||||
|
||||
if ($config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid));
|
||||
}
|
||||
?>
|
||||
<div class="osm-item-wrapper <?php echo $clearfixClass; ?>">
|
||||
<div class="osm-item-heading-box <?php echo $clearfixClass; ?>">
|
||||
<h2 class="osm-item-title">
|
||||
<a href="<?php echo $url; ?>" title="<?php echo $item->title; ?>">
|
||||
<?php echo $item->title; ?>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="osm-item-description <?php echo $clearfixClass; ?>">
|
||||
<div class="<?php echo $rowFluidClass; ?>">
|
||||
<?php
|
||||
if ($showPlanInformation && $planInformationPosition == 1)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $rightClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/plan_information.php', ['item' => $item]); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="osm-description-details <?php echo $leftClass; ?>">
|
||||
<?php
|
||||
if ($item->thumb)
|
||||
{
|
||||
?>
|
||||
<img src="<?php echo $imgSrc; ?>" alt="<?php echo $item->title; ?>" class="osm-thumb-left <?php echo $imgClass; ?>"/>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($item->short_description)
|
||||
{
|
||||
echo $item->short_description;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $item->description;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
if ($showPlanInformation && in_array($planInformationPosition, [0, 2]))
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $rightClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/plan_information.php', ['item' => $item]); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="osm-taskbar <?php echo $clearfixClass; ?>">
|
||||
<ul>
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if (count($actions))
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="<?php echo $btnPrimaryClass; ?>">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="<?php echo $btnPrimaryClass; ?>">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($config->hide_details_button))
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $url; ?>" class="<?php echo $btnClass; ?>">
|
||||
<?php echo Text::_('OSM_DETAILS'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $rowMembers
|
||||
*/
|
||||
|
||||
$names = [];
|
||||
|
||||
foreach ($rowMembers as $rowMember)
|
||||
{
|
||||
$names[] = trim($rowMember->first_name . ' ' . $rowMember->last_name);
|
||||
}
|
||||
|
||||
echo implode("\r\n", $names);
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var string $redirectHeading
|
||||
* @var string $url
|
||||
* @var bool $newWindow
|
||||
* @var array $data
|
||||
*/
|
||||
?>
|
||||
<div class="payment-heading"><?php echo $redirectHeading; ?></div>
|
||||
<form method="post" action="<?php echo $url; ?>" name="payment_form"
|
||||
id="payment_form"<?php if ($newWindow) echo ' target="_blank"'; ?>>
|
||||
<?php
|
||||
foreach ($data as $key => $val)
|
||||
{
|
||||
echo '<input type="hidden" name="' . $key . '" value="' . $val . '" />';
|
||||
echo "\n";
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
document.payment_form.submit();
|
||||
</script>
|
||||
</form>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var stdClass $item
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
try
|
||||
{
|
||||
$form = Form::getInstance('plan_fields', JPATH_ROOT . '/components/com_osmembership/fields.xml', [], false, '//config');
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($form->getFieldset('basic') as $field)
|
||||
{
|
||||
if ($field->getAttribute('hide'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
?>
|
||||
<tr class="osm-plan-property">
|
||||
<td class="osm-plan-property-label">
|
||||
<?php echo Text::_($field->getAttribute('label')); ?>:
|
||||
</td>
|
||||
<td class="osm-plan-property-value">
|
||||
<?php echo $item->fieldsData->get($field->getAttribute('name')); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var stdClass $item
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$config = OSMembershipHelper::getConfig();
|
||||
$symbol = $item->currency_symbol ?: $item->currency;
|
||||
?>
|
||||
<table class="<?php echo $bootstrapHelper->getClassMapping('table table-striped table-bordered'); ?>">
|
||||
<?php
|
||||
if ($item->setup_fee > 0)
|
||||
{
|
||||
?>
|
||||
<tr class="osm-plan-property">
|
||||
<td class="osm-plan-property-label">
|
||||
<?php echo Text::_('OSM_SETUP_FEE'); ?>:
|
||||
</td>
|
||||
<td class="osm-plan-property-value">
|
||||
<?php echo OSMembershipHelper::formatCurrency($item->setup_fee, $config, $symbol); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($item->recurring_subscription && $item->trial_duration)
|
||||
{
|
||||
?>
|
||||
<tr class="osm-plan-property">
|
||||
<td class="osm-plan-property-label">
|
||||
<?php echo Text::_('OSM_TRIAL_DURATION'); ?>:
|
||||
</td>
|
||||
<td class="osm-plan-property-value">
|
||||
<?php
|
||||
if ($item->lifetime_membership)
|
||||
{
|
||||
echo Text::_('OSM_LIFETIME');
|
||||
}
|
||||
else
|
||||
{
|
||||
echo OSMembershipHelperSubscription::getDurationText($item->trial_duration, $item->trial_duration_unit);
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="osm-plan-property">
|
||||
<td class="osm-plan-property-label">
|
||||
<?php echo Text::_('OSM_TRIAL_PRICE'); ?>:
|
||||
</td>
|
||||
<td class="osm-plan-property-value">
|
||||
<?php
|
||||
if ($item->trial_amount > 0)
|
||||
{
|
||||
echo OSMembershipHelper::formatCurrency($item->trial_amount, $config, $symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo Text::_('OSM_FREE');
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!((int) $item->expired_date))
|
||||
{
|
||||
?>
|
||||
<tr class="osm-plan-property">
|
||||
<td class="osm-plan-property-label">
|
||||
<?php echo Text::_('OSM_DURATION'); ?>:
|
||||
</td>
|
||||
<td class="osm-plan-property-value">
|
||||
<?php
|
||||
if ($item->lifetime_membership)
|
||||
{
|
||||
echo Text::_('OSM_LIFETIME');
|
||||
}
|
||||
else
|
||||
{
|
||||
echo OSMembershipHelperSubscription::getDurationText($item->subscription_length, $item->subscription_length_unit);
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<tr class="osm-plan-property">
|
||||
<td class="osm-plan-property-label">
|
||||
<?php echo Text::_('OSM_PRICE'); ?>:
|
||||
</td>
|
||||
<td class="osm-plan-property-value">
|
||||
<?php
|
||||
if ($item->price > 0)
|
||||
{
|
||||
echo OSMembershipHelper::formatCurrency($item->price, $config, $symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo Text::_('OSM_FREE');
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
if (file_exists(JPATH_ROOT . '/components/com_osmembership/fields.xml')
|
||||
&& filesize(JPATH_ROOT . '/components/com_osmembership/fields.xml'))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/plan_custom_fields.php', ['item' => $item]);
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var stdClass $item
|
||||
*/
|
||||
|
||||
$config = OSMembershipHelper::getConfig();
|
||||
|
||||
$dec_point = $config->dec_point ?? '.';
|
||||
$thousands_sep = $config->thousands_sep ?? ',';
|
||||
|
||||
if ($item->lifetime_membership)
|
||||
{
|
||||
$subscriptionLengthText = Text::_('OSM_LIFETIME');
|
||||
}
|
||||
else
|
||||
{
|
||||
$subscriptionLengthText = OSMembershipHelperSubscription::getDurationText($item->subscription_length, $item->subscription_length_unit, false);
|
||||
}
|
||||
|
||||
if ($item->price > 0)
|
||||
{
|
||||
$priceParts = explode('.', $item->price);
|
||||
|
||||
if ($priceParts[1] == '00' || $config->decimals === '0')
|
||||
{
|
||||
$numberDecimals = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberDecimals = 2;
|
||||
}
|
||||
|
||||
$symbol = $item->currency_symbol ?: $item->currency;
|
||||
|
||||
if (!$symbol)
|
||||
{
|
||||
$symbol = $config->currency_symbol;
|
||||
}
|
||||
|
||||
if ($config->currency_position == 0)
|
||||
{
|
||||
echo $symbol . number_format($item->price, $numberDecimals, $dec_point, $thousands_sep) . ($subscriptionLengthText ? "<sub>/$subscriptionLengthText</sub>" : '');
|
||||
}
|
||||
else
|
||||
{
|
||||
echo number_format($item->price, $numberDecimals, $dec_point, $thousands_sep) . $symbol . ($subscriptionLengthText ? "<sub>/$subscriptionLengthText</sub>" : '');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo Text::_('OSM_FREE') . ($subscriptionLengthText ? "<sub> /$subscriptionLengthText</sub>" : '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var MPFInput $input
|
||||
* @var MPFConfig $config
|
||||
* @var int $Itemid
|
||||
* @var int $categoryId
|
||||
* @var OSMembershipHelperBootstrap $bootstrapHelper
|
||||
*/
|
||||
|
||||
$rootUri = Uri::root(true);
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
if (empty($params))
|
||||
{
|
||||
$params = Factory::getApplication()->getParams();
|
||||
}
|
||||
|
||||
if (isset($input) && $input->getInt('recommended_plan_id'))
|
||||
{
|
||||
$recommendedPlanId = $input->getInt('recommended_plan_id');
|
||||
}
|
||||
else
|
||||
{
|
||||
$recommendedPlanId = (int) $params->get('recommended_campaign_id');
|
||||
}
|
||||
|
||||
$standardPlanBackgroundColor = $params->get('standard_plan_color', '#00B69C');
|
||||
$recommendedPlanBackgroundColor = $params->get('recommended_plan_color', '#bF75500');
|
||||
$showDetailsButton = $params->get('show_details_button', 0);
|
||||
|
||||
if (isset($input) && $input->getInt('number_columns'))
|
||||
{
|
||||
$numberColumns = $input->getInt('number_columns');
|
||||
}
|
||||
elseif (isset($config->number_columns))
|
||||
{
|
||||
$numberColumns = $config->number_columns;
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberColumns = 3;
|
||||
}
|
||||
|
||||
$numberColumns = min($numberColumns, 5);
|
||||
|
||||
if (!isset($categoryId))
|
||||
{
|
||||
$categoryId = 0;
|
||||
}
|
||||
|
||||
$span = intval(12 / $numberColumns);
|
||||
$imgClass = $bootstrapHelper->getClassMapping('img-polaroid');
|
||||
$spanClass = $bootstrapHelper->getClassMapping('span' . $span);
|
||||
|
||||
$i = 0;
|
||||
$numberPlans = count($items);
|
||||
$defaultItemId = $Itemid;
|
||||
$rootUri = Uri::root(true);
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$Itemid = OSMembershipHelperRoute::getPlanMenuId($item->id, $item->category_id, $defaultItemId);
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = $rootUri . '/media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&catid=' . $item->category_id . '&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
|
||||
if ($config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid));
|
||||
}
|
||||
|
||||
if (!$item->short_description)
|
||||
{
|
||||
$item->short_description = $item->description;
|
||||
}
|
||||
|
||||
if ($item->id == $recommendedPlanId)
|
||||
{
|
||||
$recommended = true;
|
||||
$backgroundColor = $recommendedPlanBackgroundColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
$recommended = false;
|
||||
$backgroundColor = $standardPlanBackgroundColor;
|
||||
}
|
||||
|
||||
if ($i % $numberColumns == 0)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $bootstrapHelper->getClassMapping('row-fluid clearfix'); ?> osm-pricing-table-circle">
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo $spanClass; ?>">
|
||||
<div class="osm-plan osm-plan-<?php echo $item->id; ?>">
|
||||
<div class="osm-plan-header" style="background-color: <?php echo $backgroundColor; ?>">
|
||||
<h2 class="osm-plan-title">
|
||||
<?php echo $item->title; ?>
|
||||
</h2>
|
||||
<div class="osm-plan-price" style="background-color: <?php echo $backgroundColor; ?>">
|
||||
<p class="price">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/priceduration.php', ['item' => $item]); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="osm-plan-short-description">
|
||||
<?php echo $item->short_description;?>
|
||||
</div>
|
||||
<ul class="osm-signup-container">
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if(count($actions))
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="btn-signup" style="background-color: <?php echo $backgroundColor; ?>">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="btn-signup" style="background-color: <?php echo $backgroundColor; ?>">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
if ($showDetailsButton)
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $url; ?>" class="btn-signup" style="background-color: <?php echo $backgroundColor; ?>">
|
||||
<?php echo Text::_('OSM_DETAILS'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (($i + 1) % $numberColumns == 0)
|
||||
{
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($i % $numberColumns != 0)
|
||||
{
|
||||
echo '</div>' ;
|
||||
}
|
||||
?>
|
||||
<style type="text/css">
|
||||
.osm-pricing-table-circle .osm-plan:hover .osm-plan-price {
|
||||
background-color: <?php echo $recommendedPlanBackgroundColor; ?>!important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,233 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var MPFInput $input
|
||||
* @var MPFConfig $config
|
||||
* @var int $Itemid
|
||||
* @var int $categoryId
|
||||
* @var OSMembershipHelperBootstrap $bootstrapHelper
|
||||
*/
|
||||
|
||||
// Load equals height script
|
||||
$rootUri = Uri::root(true);
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
if (empty($params))
|
||||
{
|
||||
$params = Factory::getApplication()->getParams();
|
||||
}
|
||||
|
||||
if (isset($input) && $input->getInt('recommended_plan_id'))
|
||||
{
|
||||
$recommendedPlanId = $input->getInt('recommended_plan_id');
|
||||
}
|
||||
else
|
||||
{
|
||||
$recommendedPlanId = (int) $params->get('recommended_campaign_id');
|
||||
}
|
||||
|
||||
$standardPlanBackgroundColor = $params->get('standard_plan_color', '#00B69C');
|
||||
$recommendedPlanBackgroundColor = $params->get('recommended_plan_color', '#F75500');
|
||||
$showDetailsButton = $params->get('show_details_button', 0);
|
||||
|
||||
if (isset($input) && $input->getInt('number_columns'))
|
||||
{
|
||||
$numberColumns = $input->getInt('number_columns');
|
||||
}
|
||||
elseif (isset($config->number_columns))
|
||||
{
|
||||
$numberColumns = $config->number_columns;
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberColumns = 3;
|
||||
}
|
||||
|
||||
$numberColumns = min($numberColumns, 5);
|
||||
|
||||
if (!isset($categoryId))
|
||||
{
|
||||
$categoryId = 0;
|
||||
}
|
||||
|
||||
$span = intval(12 / $numberColumns);
|
||||
$imgClass = $bootstrapHelper->getClassMapping('img-polaroid');
|
||||
$spanClass = $bootstrapHelper->getClassMapping('span' . $span);
|
||||
|
||||
$i = 0;
|
||||
$numberPlans = count($items);
|
||||
$defaultItemId = $Itemid;
|
||||
$rootUri = Uri::root(true);
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$Itemid = OSMembershipHelperRoute::getPlanMenuId($item->id, $item->category_id, $defaultItemId);
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = $rootUri . '/media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&catid=' . $item->category_id . '&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
|
||||
if ($config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid));
|
||||
}
|
||||
|
||||
if (!$item->short_description)
|
||||
{
|
||||
$item->short_description = $item->description;
|
||||
}
|
||||
|
||||
if ($item->id == $recommendedPlanId)
|
||||
{
|
||||
$recommended = true;
|
||||
$backgroundColor = $recommendedPlanBackgroundColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
$recommended = false;
|
||||
$backgroundColor = $standardPlanBackgroundColor;
|
||||
}
|
||||
|
||||
if ($i % $numberColumns == 0)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $bootstrapHelper->getClassMapping('row-fluid clearfix'); ?> osm-pricing-table-flat">
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo $spanClass; ?>">
|
||||
<div class="osm-plan osm-plan-<?php echo $item->id; ?>" style="background-color: <?php echo $backgroundColor; ?>">
|
||||
<div class="osm-plan-header">
|
||||
<h2 class="osm-plan-title">
|
||||
<?php echo $item->title; ?>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="osm-plan-price">
|
||||
<p class="price">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/priceduration.php', ['item' => $item]); ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="osm-plan-short-description">
|
||||
<?php echo $item->short_description;?>
|
||||
</div>
|
||||
<ul class="osm-signup-container">
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if (count($actions))
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="btn-signup">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="btn-signup">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
if ($showDetailsButton)
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $url; ?>" class="btn-signup oms-btn-details">
|
||||
<?php echo Text::_('OSM_DETAILS'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (($i + 1) % $numberColumns == 0)
|
||||
{
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($i % $numberColumns != 0)
|
||||
{
|
||||
echo '</div>' ;
|
||||
}
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $items
|
||||
* @var MPFInput $input
|
||||
* @var MPFConfig $config
|
||||
* @var int $Itemid
|
||||
* @var int $categoryId
|
||||
* @var OSMembershipHelperBootstrap $bootstrapHelper
|
||||
*/
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
if (empty($params))
|
||||
{
|
||||
$params = Factory::getApplication()->getParams();
|
||||
}
|
||||
|
||||
// Background color settings
|
||||
$badgeBgColor = $params->get('recommended_badge_background_color');
|
||||
$headerBgColor = $params->get('header_background_color');
|
||||
$priceBgColor = $params->get('price_background_color');
|
||||
$recommendedPriceBgColor = $params->get('recommended_plan_price_background_color');
|
||||
|
||||
if (isset($input) && $input->getInt('recommended_plan_id'))
|
||||
{
|
||||
$recommendedPlanId = $input->getInt('recommended_plan_id');
|
||||
}
|
||||
else
|
||||
{
|
||||
$recommendedPlanId = (int) $params->get('recommended_campaign_id');
|
||||
}
|
||||
|
||||
$showDetailsButton = $params->get('show_details_button', 0);
|
||||
|
||||
if (isset($input) && $input->getInt('number_columns'))
|
||||
{
|
||||
$numberColumns = $input->getInt('number_columns');
|
||||
}
|
||||
elseif (isset($config->number_columns))
|
||||
{
|
||||
$numberColumns = $config->number_columns ;
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberColumns = 3 ;
|
||||
}
|
||||
|
||||
$numberColumns = min($numberColumns, 4);
|
||||
|
||||
if (!isset($categoryId))
|
||||
{
|
||||
$categoryId = 0;
|
||||
}
|
||||
|
||||
$span = intval(12 / $numberColumns);
|
||||
|
||||
$btnClass = $bootstrapHelper->getClassMapping('btn');
|
||||
$btnPrimaryClass = $bootstrapHelper->getClassMapping('btn btn-primary');
|
||||
$imgClass = $bootstrapHelper->getClassMapping('img-polaroid');
|
||||
$spanClass = $bootstrapHelper->getClassMapping('span' . $span);
|
||||
|
||||
$rootUri = Uri::root(true);
|
||||
$i = 0;
|
||||
$numberPlans = count($items);
|
||||
$defaultItemId = $Itemid;
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$Itemid = OSMembershipHelperRoute::getPlanMenuId($item->id, $item->category_id, $defaultItemId);
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = $rootUri . '/media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
$url = Route::_('index.php?option=com_osmembership&view=plan&catid=' . $item->category_id . '&id=' . $item->id . '&Itemid=' . $Itemid);
|
||||
|
||||
if ($config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $Itemid));
|
||||
}
|
||||
|
||||
if (!$item->short_description)
|
||||
{
|
||||
$item->short_description = $item->description;
|
||||
}
|
||||
|
||||
if ($item->id == $recommendedPlanId)
|
||||
{
|
||||
$recommended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$recommended = false;
|
||||
}
|
||||
|
||||
if ($recommended && $recommendedPriceBgColor)
|
||||
{
|
||||
$planPriceBackgroundColor = $recommendedPriceBgColor;
|
||||
}
|
||||
elseif ($priceBgColor)
|
||||
{
|
||||
$planPriceBackgroundColor = $priceBgColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
$planPriceBackgroundColor = '';
|
||||
}
|
||||
|
||||
if ($i % $numberColumns == 0)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $bootstrapHelper->getClassMapping('row-fluid clearfix'); ?> osm-pricing-table">
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo $spanClass; ?>">
|
||||
<div class="osm-plan<?php if ($recommended) echo ' osm-plan-recommended'; ?> osm-plan-<?php echo $item->id; ?>">
|
||||
<?php
|
||||
if ($recommended)
|
||||
{
|
||||
?>
|
||||
<p class="plan-recommended"<?php if ($badgeBgColor) echo ' style=" background-color:' . $badgeBgColor . '";'; ?>><?php echo Text::_('OSM_RECOMMENDED'); ?></p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="osm-plan-header"<?php if ($headerBgColor) echo ' style=" background-color:' . $headerBgColor . '";'; ?>>
|
||||
<h2 class="osm-plan-title">
|
||||
<?php echo $item->title; ?>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="osm-plan-price"<?php if ($planPriceBackgroundColor) echo ' style=" background-color:' . $planPriceBackgroundColor . '";'; ?>>
|
||||
<h2>
|
||||
<p class="price">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/priceduration.php', ['item' => $item]); ?>
|
||||
</p>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="osm-plan-short-description">
|
||||
<?php echo $item->short_description;?>
|
||||
</div>
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if (count($actions) || $showDetailsButton)
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
?>
|
||||
<ul class="osm-signup-container">
|
||||
<?php
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="<?php echo $btnPrimaryClass; ?> btn-singup">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="<?php echo $btnPrimaryClass; ?> btn-singup">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($showDetailsButton)
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $url; ?>" class="<?php echo $btnClass; ?>">
|
||||
<?php echo Text::_('OSM_DETAILS'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (($i + 1) % $numberColumns == 0)
|
||||
{
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($i % $numberColumns != 0)
|
||||
{
|
||||
echo '</div>' ;
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
?>
|
||||
<ul class="osm-renew-options">
|
||||
<?php
|
||||
$userId = Factory::getApplication()->getIdentity()->id;
|
||||
$renewOptionCount = 0;
|
||||
$fieldSuffix = OSMembershipHelper::getFieldSuffix();
|
||||
|
||||
foreach ($this->planIds as $planId)
|
||||
{
|
||||
$plan = $this->plans[$planId];
|
||||
$taxRate = 0;
|
||||
|
||||
if ($this->config->show_price_including_tax && !$this->config->setup_price_including_tax)
|
||||
{
|
||||
$taxRate = OSMembershipHelper::calculateMaxTaxRate($planId);
|
||||
}
|
||||
|
||||
$symbol = $plan->currency_symbol ?: $plan->currency;
|
||||
$renewOptions = $this->renewOptions[$planId] ?? [];
|
||||
|
||||
if (count($renewOptions))
|
||||
{
|
||||
foreach ($renewOptions as $renewOption)
|
||||
{
|
||||
$checked = '';
|
||||
|
||||
if ($renewOptionCount == 0)
|
||||
{
|
||||
$checked = ' checked="checked" ';
|
||||
}
|
||||
|
||||
$renewOptionCount++;
|
||||
$renewOptionLengthText = OSMembershipHelperSubscription::getDurationText($renewOption->renew_option_length, $renewOption->renew_option_length_unit);
|
||||
|
||||
$renewOptionText = Text::sprintf('OSM_RENEW_OPTION_TEXT', $plan->title, $renewOptionLengthText, OSMembershipHelper::formatCurrency($renewOption->price * (1 + $taxRate / 100), $this->config, $symbol));
|
||||
|
||||
if (strpos($renewOptionText, '[EXPIRED_DATE]'))
|
||||
{
|
||||
$expiredDate = OSMembershipHelperSubscription::getPlanExpiredDate($planId);
|
||||
|
||||
if ($expiredDate)
|
||||
{
|
||||
$expiredDate = HTMLHelper::_('date', $expiredDate, $this->config->date_format);
|
||||
}
|
||||
|
||||
$renewOptionText = str_replace('[EXPIRED_DATE]', $expiredDate, $renewOptionText);
|
||||
}
|
||||
?>
|
||||
<li class="osm-renew-option">
|
||||
<input type="radio" class="validate[required]<?php echo $this->bootstrapHelper->getFrameworkClass('uk-radio', 1); ?>" id="renew_option_id_<?php echo $renewOptionCount; ?>" name="renew_option_id" value="<?php echo $planId . '|' . $renewOption->id; ?>" <?php echo $checked; ?> />
|
||||
<label for="renew_option_id_<?php echo $renewOptionCount; ?>"><?php echo $renewOptionText; ?></label>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$checked = '';
|
||||
|
||||
if ($renewOptionCount == 0)
|
||||
{
|
||||
$checked = ' checked="checked" ';
|
||||
}
|
||||
|
||||
$renewOptionCount++;
|
||||
$subscriptionLengthText = OSMembershipHelperSubscription::getDurationText($plan->subscription_length, $plan->subscription_length_unit);
|
||||
|
||||
$renewalDiscountRule = OSMembershipHelperSubscription::getRenewalDiscount($userId, $planId);
|
||||
|
||||
if ($renewalDiscountRule)
|
||||
{
|
||||
if ($renewalDiscountRule->discount_type == 0)
|
||||
{
|
||||
$plan->price = round($plan->price * (1 - $renewalDiscountRule->discount_amount / 100), 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
$plan->price = $plan->price - $renewalDiscountRule->discount_amount;
|
||||
}
|
||||
|
||||
if ($plan->price < 0)
|
||||
{
|
||||
$plan->price = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$renewOptionText = Text::sprintf('OSM_RENEW_OPTION_TEXT', $plan->title, $subscriptionLengthText, OSMembershipHelper::formatCurrency($plan->price * (1 + $taxRate / 100), $this->config, $symbol));
|
||||
|
||||
if (strpos($renewOptionText, '[EXPIRED_DATE]'))
|
||||
{
|
||||
$expiredDate = OSMembershipHelperSubscription::getPlanExpiredDate($plan->id);
|
||||
|
||||
if ($expiredDate)
|
||||
{
|
||||
$expiredDate = HTMLHelper::_('date', $expiredDate, $this->config->date_format);
|
||||
}
|
||||
|
||||
$renewOptionText = str_replace('[EXPIRED_DATE]', $expiredDate, $renewOptionText);
|
||||
}
|
||||
?>
|
||||
<li class="osm-renew-option">
|
||||
<input type="radio" class="validate[required]<?php echo $this->bootstrapHelper->getFrameworkClass('uk-radio', 1); ?>" id="renew_option_id_<?php echo $renewOptionCount; ?>" name="renew_option_id" value="<?php echo $planId;?>" <?php echo $checked; ?>/>
|
||||
<label for="renew_option_id_<?php echo $renewOptionCount; ?>"><?php echo $renewOptionText; ?></label>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<div class="form-actions">
|
||||
<input type="submit" class="<?php echo $this->bootstrapHelper->getClassMapping('btn btn-primary'); ?>" value="<?php echo Text::_('OSM_PROCESS_RENEW'); ?>"/>
|
||||
</div>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var string $introText
|
||||
* @var string $msg
|
||||
* @var string $context
|
||||
* @var stdClass $row
|
||||
*/
|
||||
|
||||
if (isset($introText))
|
||||
{
|
||||
echo '<div class="intro-text">' . $introText . '</div>';
|
||||
}
|
||||
?>
|
||||
<div class="text-info">
|
||||
<?php echo $msg; ?>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var bool $showPagination
|
||||
* @var \Joomla\CMS\Pagination\Pagination $pagination
|
||||
*/
|
||||
|
||||
/* @var \Joomla\Database\DatabaseDriver $db */
|
||||
$db = Factory::getContainer()->get('db');
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__osmembership_plugins')
|
||||
->where('published = 1')
|
||||
->where('name NOT LIKE "os_offline%"');
|
||||
$db->setQuery($query);
|
||||
$hasOnlinePaymentPlugin = $db->loadResult() > 0;
|
||||
|
||||
$makePaymentItemid = OSMembershipHelperRoute::getViewRoute('payment', $this->Itemid);
|
||||
|
||||
$cols = 5;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$centerClass = $bootstrapHelper->getClassMapping('center');
|
||||
$hiddenPhoneClass = $bootstrapHelper->getClassMapping('hidden-phone');
|
||||
?>
|
||||
<table class="<?php echo $bootstrapHelper->getClassMapping('table table-striped table-bordered') ?>">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<?php echo Text::_('OSM_PLAN') ?>
|
||||
</th>
|
||||
<th class="<?php echo $centerClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_DATE') ; ?>
|
||||
</th>
|
||||
<th class="<?php echo $centerClass; ?>">
|
||||
<?php echo Text::_('OSM_ACTIVATE_TIME') ; ?>
|
||||
</th>
|
||||
<th style="text-align: right;" class="<?php echo $hiddenPhoneClass; ?>">
|
||||
<?php echo Text::_('OSM_GROSS_AMOUNT') ; ?>
|
||||
</th>
|
||||
<th class="<?php echo $hiddenPhoneClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_STATUS'); ?>
|
||||
</th>
|
||||
<?php
|
||||
if ($this->config->activate_invoice_feature)
|
||||
{
|
||||
$cols++ ;
|
||||
?>
|
||||
<th class="<?php echo $hiddenPhoneClass . ' ' . $centerClass; ?>">
|
||||
<?php echo Text::_('OSM_INVOICE_NUMBER') ; ?>
|
||||
</th>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$k = 0 ;
|
||||
for ($i = 0 , $n = count($this->items) ; $i < $n ; $i++) {
|
||||
$row = $this->items[$i];
|
||||
$k = 1 - $k;
|
||||
$link = Route::_('index.php?option=com_osmembership&view=subscription&id=' . $row->id . '&Itemid=' . $this->Itemid);
|
||||
$symbol = $row->currency_symbol ?: $row->currency;
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo $link; ?>"><?php echo $row->plan_title; ?></a>
|
||||
</td>
|
||||
<td class="<?php echo $centerClass; ?>">
|
||||
<?php echo HTMLHelper::_('date', $row->created_date, $this->config->date_format); ?>
|
||||
</td>
|
||||
<td class="<?php echo $centerClass; ?>">
|
||||
<strong><?php echo HTMLHelper::_('date', $row->from_date, $this->config->date_format); ?></strong> <?php echo Text::_('OSM_TO'); ?>
|
||||
<strong>
|
||||
<?php
|
||||
if ($row->lifetime_membership || $row->to_date == '2099-12-31 23:59:59')
|
||||
{
|
||||
echo Text::_('OSM_LIFETIME');
|
||||
}
|
||||
else
|
||||
{
|
||||
echo HTMLHelper::_('date', $row->to_date, $this->config->date_format);
|
||||
}
|
||||
?>
|
||||
</strong>
|
||||
</td>
|
||||
<td style="text-align: right;" class="<?php echo $hiddenPhoneClass; ?>">
|
||||
<?php echo OSMembershipHelper::formatCurrency($row->gross_amount, $this->config, $symbol)?>
|
||||
</td>
|
||||
<td class="<?php echo $hiddenPhoneClass; ?>">
|
||||
<?php
|
||||
switch ($row->published)
|
||||
{
|
||||
case 0 :
|
||||
echo Text::_('OSM_PENDING');
|
||||
|
||||
if ($this->config->enable_subscription_payment && $row->gross_amount > 0 && $hasOnlinePaymentPlugin)
|
||||
{
|
||||
?>
|
||||
<br /><a class="<?php echo $bootstrapHelper->getClassMapping('btn btn-primary'); ?>" href="<?php echo Route::_('index.php?option=com_osmembership&view=payment&transaction_id=' . $row->transaction_id . '&Itemid=' . $makePaymentItemid); ?>"><?php echo Text::_('OSM_MAKE_PAYMENT'); ?></a>
|
||||
<?php
|
||||
}
|
||||
|
||||
break;
|
||||
case 1 :
|
||||
echo Text::_('OSM_ACTIVE');
|
||||
break;
|
||||
case 2 :
|
||||
echo Text::_('OSM_EXPIRED');
|
||||
break;
|
||||
case 3 :
|
||||
echo Text::_('OSM_CANCELLED_PENDING');
|
||||
break;
|
||||
case 4 :
|
||||
echo Text::_('OSM_CANCELLED_REFUNDED');
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<?php
|
||||
if ($this->config->activate_invoice_feature)
|
||||
{
|
||||
?>
|
||||
<td class="<?php echo $hiddenPhoneClass . ' ' . $centerClass; ?>">
|
||||
<?php
|
||||
if ($row->invoice_number)
|
||||
{
|
||||
?>
|
||||
<a href="<?php echo Route::_('index.php?option=com_osmembership&task=download_invoice&id=' . $row->id); ?>" title="<?php echo Text::_('OSM_DOWNLOAD'); ?>"><?php echo OSMembershipHelper::formatInvoiceNumber($row, $this->config); ?></a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<?php
|
||||
if ($showPagination && ($pagination->total > $pagination->limit))
|
||||
{
|
||||
?>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="<?php echo $cols; ?>">
|
||||
<div class="pagination"><?php echo $this->pagination->getListFooter(); ?></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
*
|
||||
* @var array $rows
|
||||
* @var array $fields
|
||||
*/
|
||||
|
||||
$config = OSMembershipHelper::getConfig();
|
||||
$i = 1;
|
||||
?>
|
||||
<p style="padding-bottom: 20px; text-align: center;">
|
||||
<h1><?php echo Text::_('OSM_SUBSCRIPTIONS_LIST'); ?></h1>
|
||||
</p>
|
||||
<table border="1" width="100%" cellspacing="0" cellpadding="2" style="margin-top: 100px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="3%" height="20" style="text-align: center;">
|
||||
No
|
||||
</th>
|
||||
<th height="20" width="8%">
|
||||
<?php echo Text::_('OSM_FIRSTNAME'); ?>
|
||||
</th height="20">
|
||||
<th height="20" width="10%">
|
||||
<?php echo Text::_('OSM_LASTNAME'); ?>
|
||||
</th height="20">
|
||||
<th height="20" width="20%">
|
||||
<?php echo Text::_('OSM_PLAN'); ?>
|
||||
</th>
|
||||
<th height="20" width="17%" style="text-align: center">
|
||||
<?php echo Text::_('OSM_START_DATE') . ' / ' . Text::_('OSM_END_DATE'); ?>
|
||||
</th>
|
||||
<th height="20" width="16%">
|
||||
<?php echo Text::_('OSM_EMAIL'); ?>
|
||||
</th>
|
||||
<th height="20" width="9%" style="text-align: center;">
|
||||
<?php echo Text::_('OSM_CREATED_DATE'); ?>
|
||||
</th>
|
||||
<th width="6%" height="20" style="text-align: right;">
|
||||
<?php echo Text::_('OSM_GROSS_AMOUNT'); ?>
|
||||
</th>
|
||||
<th width="8%" height="20">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_STATUS'); ?>
|
||||
</th>
|
||||
<th width="3%" height="20" style="text-align: center;">
|
||||
<?php echo Text::_('OSM_ID'); ?>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
?>
|
||||
<tr>
|
||||
<td width="3%" style="text-align: center;"><?php echo $i++; ?></td>
|
||||
<td width="8%"><?php echo $row->first_name; ?></td>
|
||||
<td width="10%"><?php echo $row->last_name; ?></td>
|
||||
<td width="20%;"><?php echo $row->plan; ?></td>
|
||||
<td width="17%" style="text-align: center"><?php echo $row->from_date . ' / ' . $row->to_date; ?></td>
|
||||
<td width="16%"><?php echo $row->email; ?></td>
|
||||
<td width="9%" style="text-align: center;"><?php echo $row->created_date; ?></td>
|
||||
<td width="6%" style="text-align: right;"><?php echo $row->amount; ?></td>
|
||||
<th width="8%" height="20">
|
||||
<?php
|
||||
switch ($row->published)
|
||||
{
|
||||
case 0:
|
||||
echo Text::_('OSM_PENDING');
|
||||
break;
|
||||
case 1:
|
||||
echo Text::_('OSM_ACTIVE');
|
||||
break;
|
||||
case 2:
|
||||
echo Text::_('OSM_EXPIRED');
|
||||
break;
|
||||
case 3 :
|
||||
echo Text::_('OSM_CANCELLED_PENDING');
|
||||
break ;
|
||||
case 4 :
|
||||
echo Text::_('OSM_CANCELLED_REFUNDED');
|
||||
break ;
|
||||
}
|
||||
?>
|
||||
</th>
|
||||
<td width="3%" style="text-align: center;"><?php echo $row->id; ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
?>
|
||||
<ul class="osm-upgrade-options">
|
||||
<?php
|
||||
$upgradeOptionCount = 0;
|
||||
|
||||
foreach ($this->upgradeRules as $rule)
|
||||
{
|
||||
$checked = '';
|
||||
|
||||
if ($upgradeOptionCount == 0)
|
||||
{
|
||||
$checked = ' checked="checked" ';
|
||||
}
|
||||
|
||||
$upgradeOptionCount++;
|
||||
$upgradeToPlan = $this->plans[$rule->to_plan_id];
|
||||
$symbol = $upgradeToPlan->currency_symbol ?: $upgradeToPlan->currency;
|
||||
|
||||
$taxRate = 0;
|
||||
|
||||
if ($this->config->show_price_including_tax && !$this->config->setup_price_including_tax)
|
||||
{
|
||||
$taxRate = OSMembershipHelper::calculateMaxTaxRate($rule->to_plan_id);
|
||||
}
|
||||
?>
|
||||
<li class="osm-upgrade-option">
|
||||
<input type="radio" class="validate[required]<?php echo $this->bootstrapHelper->getFrameworkClass('uk-radio', 1);?>" id="upgrade_option_id_<?php echo $upgradeOptionCount; ?>" name="upgrade_option_id" value="<?php echo $rule->id; ?>"<?php echo $checked; ?> />
|
||||
<label for="upgrade_option_id_<?php echo $upgradeOptionCount; ?>"><?php Text::printf('OSM_UPGRADE_OPTION_TEXT', $this->plans[$rule->from_plan_id]->title, $upgradeToPlan->title, OSMembershipHelper::formatCurrency($rule->price * (1 + $taxRate / 100), $this->config, $symbol)); ?></label>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,141 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
defined('_JEXEC') or die ;
|
||||
|
||||
use Joomla\CMS\Editor\Editor;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Toolbar\Toolbar;
|
||||
|
||||
HTMLHelper::_('bootstrap.tooltip', '.hasTooltip', ['html' => true, 'sanitize' => false]);
|
||||
|
||||
$config = OSMembershipHelper::getConfig();
|
||||
$editor = Editor::getInstance($config->get('editor') ?: Factory::getApplication()->get('editor'));
|
||||
$translatable = Multilanguage::isEnabled() && count($this->languages);
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluid = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$span8 = $bootstrapHelper->getClassMapping('span7');
|
||||
$span4 = $bootstrapHelper->getClassMapping('span5');
|
||||
|
||||
HTMLHelper::_('formbehavior.chosen', '.advSelect');
|
||||
|
||||
Factory::getApplication()
|
||||
->getDocument()
|
||||
->getWebAssetManager()
|
||||
->useScript('core')
|
||||
->useScript('showon')
|
||||
->registerAndUseScript('com_osmembership.site-mplan-default', 'media/com_osmembership/js/site-mplan-default.min.js');
|
||||
|
||||
$keys = ['OSM_ENTER_PLAN_TITLE', 'OSM_ENTER_SUBSCRIPTION_LENGTH', 'OSM_PRICE_REQUIRED', 'OSM_INVALID_SUBSCRIPTION_LENGTH'];
|
||||
OSMembershipHelperHtml::addJSStrings($keys);
|
||||
?>
|
||||
<div id="osm-add-edit-plan" class="osm-container">
|
||||
<h1 class="osm-page-title"><?php echo $this->item->id > 0 ? Text::_('OSM_EDIT_PLAN') : Text::_('OSM_ADD_PLAN'); ?></h1>
|
||||
<div class="btn-toolbar" id="btn-toolbar">
|
||||
<?php echo Toolbar::getInstance('toolbar')->render(); ?>
|
||||
</div>
|
||||
<form action="<?php echo Route::_('index.php?option=com_osmembership&view=mplan&Itemid=' . $this->Itemid, false); ?>" method="post" name="adminForm" id="adminForm" enctype="multipart/form-data" class="form form-horizontal">
|
||||
<?php
|
||||
echo HTMLHelper::_( 'uitab.startTabSet', 'plan', ['active' => 'basic-information-page', 'recall' => true]);
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'basic-information-page', Text::_('OSM_BASIC_INFORMATION'));
|
||||
echo $this->loadTemplate('general', ['editor' => $editor]);
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'recurring-settings-page', Text::_('OSM_RECURRING_SETTINGS'));
|
||||
echo $this->loadTemplate('recurring_settings');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'renew-options-page', Text::_('OSM_RENEW_OPTIONS'));
|
||||
echo $this->loadTemplate('renew_options');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'upgrade-options-page', Text::_('OSM_UPGRADE_OPTIONS'));
|
||||
echo $this->loadTemplate('upgrade_options');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'renewal-discounts-page', Text::_('OSM_EARLY_RENEWAL_DISCOUNTS'));
|
||||
echo $this->loadTemplate('renewal_discounts');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'reminders-settings-page', Text::_('OSM_REMINDERS_SETTINGS'));
|
||||
echo $this->loadTemplate('reminders_settings');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'group-membership-settings-page', Text::_('OSM_GROUP_MEMBERSHIP'));
|
||||
echo $this->loadTemplate('group_membership');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'advanced-settings-page', Text::_('OSM_ADVANCED_SETTINGS'));
|
||||
echo $this->loadTemplate('advanced_settings');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'metadata-page', Text::_('OSM_META_DATA'));
|
||||
echo $this->loadTemplate('metadata');
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
if ($this->config->activate_member_card_feature)
|
||||
{
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'member-card-page', Text::_('OSM_MEMBER_CARD_SETTINGS'));
|
||||
echo $this->loadTemplate('member_card', ['editor' => $editor]);
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
}
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'messages-page', Text::_('OSM_MESSAGES'));
|
||||
echo $this->loadTemplate('messages', ['editor' => $editor]);
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'reminder-messages-page', Text::_('OSM_REMINDER_MESSAGES'));
|
||||
echo $this->loadTemplate('reminder_messages', ['editor' => $editor]);
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
|
||||
if ($translatable)
|
||||
{
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'translation-page', Text::_('OSM_TRANSLATION'));
|
||||
echo $this->loadTemplate('translation', ['editor' => $editor]);
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
}
|
||||
|
||||
if (count($this->plugins))
|
||||
{
|
||||
$count = 0 ;
|
||||
|
||||
foreach ($this->plugins as $plugin)
|
||||
{
|
||||
if (is_array($plugin) && array_key_exists('title', $plugin) && array_key_exists('form', $plugin))
|
||||
{
|
||||
$count++ ;
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'tab_' . $count, Text::_($plugin['title']));
|
||||
echo $plugin['form'];
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add support for custom settings layout
|
||||
if (file_exists(__DIR__ . '/default_custom_settings.php'))
|
||||
{
|
||||
echo HTMLHelper::_( 'uitab.addTab', 'plan', 'custom-settings-page', Text::_('OSM_CUSTOM_SETTINGS'));
|
||||
echo $this->loadTemplate('custom_settings', ['editor' => $editor]);
|
||||
echo HTMLHelper::_( 'uitab.endTab');
|
||||
}
|
||||
|
||||
echo HTMLHelper::_( 'uitab.endTabSet');
|
||||
?>
|
||||
<div class="clearfix"></div>
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
<input type="hidden" name="id" value="<?php echo (int) $this->item->id; ?>"/>
|
||||
<input type="hidden" name="task" value="apply" />
|
||||
<input type="hidden" id="recurring" name="recurring" value="<?php echo (int) $this->item->recurring_subscription;?>" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('setup_fee', Text::_('OSM_SETUP_FEE'), Text::_('OSM_SETUP_FEE_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="number" class="form-control input-small" name="setup_fee" id="setup_fee" value="<?php echo $this->item->setup_fee; ?>" step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($this->item->id && !$this->item->recurring_subscription)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('subscription_start_date_option', Text::_('OSM_SUBSCRIPTION_START_DATE_OPTION'), Text::_('OSM_SUBSCRIPTION_START_DATE_OPTION_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['subscription_start_date_option'];?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['subscription_start_date_option' => '1']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('subscription_start_date', Text::_('OSM_PLAN_SUBSCRIPTION_START_DATE'), Text::_('OSM_PLAN_SUBSCRIPTION_START_DATE_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo HTMLHelper::_('calendar', $this->planParams->get('subscription_start_date'), 'subscription_start_date', 'subscription_start_date', '%Y-%m-%d %H:%M:%S') ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['subscription_start_date_option' => '2']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('subscription_start_date_field', Text::_('OSM_SUBSCRIPTION_START_DATE_FIELD'), Text::_('OSM_SUBSCRIPTION_START_DATE_FIELD_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['subscription_start_date_field'];?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('free_plan_subscription_status', Text::_('OSM_FREE_PLAN_STATUS'), Text::_('OSM_FREE_PLAN_STATUS_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['free_plan_subscription_status'];?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('login_redirect_menu_id', Text::_('OSM_LOGIN_REDIRECT'), Text::_('OSM_LOGIN_REDIRECT_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['login_redirect_menu_id']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('number_fields_per_row', Text::_('OSM_NUMBER_FIELDS_PER_ROW'), Text::_('OSM_NUMBER_FIELDS_PER_ROW_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['number_fields_per_row']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('payment_methods', Text::_('OSM_PAYMENT_METHODS'), Text::_('OSM_PAYMENT_METHODS_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['payment_methods'];?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('currency_code', Text::_('OSM_CURRENCY'), Text::_('OSM_CURRENCY_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['currency'];?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('currency_symbol', Text::_('OSM_CURRENCY_SYMBOL'), Text::_('OSM_CURRENCY_SYMBOL_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" class="form-control input-small" name="currency_symbol" id="currency_symbol" value="<?php echo $this->item->currency_symbol; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_COMPLETE_URL'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="url" class="form-control input-xxlarge" name="subscription_complete_url" value="<?php echo $this->item->subscription_complete_url; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_OFFLINE_PAYMENT_SUBSCRIPTION_COMPLETE_URL'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="url" class="form-control input-xxlarge" name="offline_payment_subscription_complete_url" value="<?php echo $this->item->offline_payment_subscription_complete_url; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('notification_emails', Text::_('OSM_NOTIFICATION_EMAILS'), Text::_('OSM_NOTIFICATION_EMAILS_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" class="form-control input-xxlarge" name="notification_emails" value="<?php echo $this->item->notification_emails; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('paypal_email', Text::_('OSM_PAYPAL_EMAIL'), Text::_('OSM_PAYPAL_EMAIL_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="email" class="form-control input-xxlarge" name="paypal_email" value="<?php echo $this->item->paypal_email; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PUBLISH_UP'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo HTMLHelper::_('calendar', $this->item->publish_up, 'publish_up', 'publish_up', $this->datePickerFormat . ' %H:%M:%S', ['class' => 'input-medium']); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PUBLISH_DOWN'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo HTMLHelper::_('calendar', $this->item->publish_down, 'publish_down', 'publish_down', $this->datePickerFormat . ' %H:%M:%S', ['class' => 'input-medium']); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_TERMS_AND_CONDITIONS_ARTICLE') ; ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getArticleInput($this->item->terms_and_conditions_article_id, 'terms_and_conditions_article_id'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('conversion_tracking_code', Text::_('OSM_CONVERSION_TRACKING_CODE'), Text::_('OSM_CONVERSION_TRACKING_CODE_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<textarea name="conversion_tracking_code" class="form-control input-large" rows="10"><?php echo $this->item->conversion_tracking_code;?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_TITLE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-xxlarge" type="text" name="title" id="title" maxlength="250" value="<?php echo $this->item->title;?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_ALIAS'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-xxlarge" type="text" name="alias" id="alias" maxlength="250" value="<?php echo $this->item->alias;?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_CATEGORY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['category_id']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PRICE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control" type="number" name="price" id="price" maxlength="250" value="<?php echo $this->item->price;?>" step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_LENGTH'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-small d-inline-block" type="number" min="1" name="subscription_length" id="subscription_length" maxlength="250" value="<?php echo $this->item->subscription_length;?>" /><?php echo $this->lists['subscription_length_unit']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_EXPIRED_DATE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo HTMLHelper::_('calendar', $this->item->expired_date, 'expired_date', 'expired_date', $this->datePickerFormat) ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ((int)$this->item->expired_date)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PRORATED_SIGNUP_COST');?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['prorated_signup_cost'];?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('grace_period', Text::_('OSM_OVERLAP_PERIOD'), Text::_('OSM_OVERLAP_PERIOD_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="input-small form-control" type="number" name="grace_period" id="grace_period" maxlength="250" value="<?php echo $this->item->grace_period;?>" /><?php echo ' ' . Text::_('OSM_DAYS'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_LIFETIME_MEMBERSHIP');?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['lifetime_membership'];?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THUMB'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="file" class="form-control" name="thumb_image" size="60" />
|
||||
<?php
|
||||
if ($this->item->thumb)
|
||||
{
|
||||
?>
|
||||
<img src="<?php echo Uri::root() . 'media/com_osmembership/' . $this->item->thumb; ?>" class="img_preview" />
|
||||
<input type="checkbox" name="del_thumb" value="1" /><?php echo Text::_('OSM_DELETE_CURRENT_THUMB'); ?>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_ENABLE_RENEWAL'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['enable_renewal']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_ACCESS'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['access']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (isset($this->lists['published']))
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PUBLISHED'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['published']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SHORT_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('short_description', $this->item->short_description, '100%', '250', '75', '10') ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('description', $this->item->description, '100%', '250', '75', '10') ; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('number_members_type', Text::_('OSM_NUMBER_MEMBER_TYPES'), Text::_('OSM_NUMBER_MEMBER_TYPES_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['number_members_type']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['number_members_type' => '0']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('number_group_members', Text::_('PLG_GRM_MAX_NUMBER_MEMBERS'), Text::_('PLG_GRM_MAX_NUMBER_MEMBERS_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="number" class="form-control input-small" name="number_group_members" id="number_group_members" value="<?php echo $this->item->number_group_members; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['number_members_type' => '1']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('number_members_field', Text::_('OSM_NUMBER_MEMBERS_FIELD'), Text::_('OSM_NUMBER_MEMBERS_FIELD_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['number_members_field']; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('activate_member_card_feature', Text::_('OSM_ACTIVATE_MEMBER_CARD_FEATURE'), Text::_('OSM_ACTIVATE_MEMBER_CARD_FEATURE_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getBooleanInput('activate_member_card_feature', $this->item->activate_member_card_feature); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_CARD_BG_IMAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getMediaInput($this->item->card_bg_image, 'card_bg_image'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_CARD_LAYOUT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('card_layout', $this->item->card_layout, '100%', '550', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<p class="text-error" style="font-size:16px;"><?php echo Text::_('OSM_PLAN_MESSAGES_EXPLAIN'); ?></p>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<strong><?php echo Text::_('OSM_PLAN_SUBSCRIPTION_FORM_MESSAGE'); ?></strong>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('subscription_form_message', $this->item->subscription_form_message, '100%', '250', '75', '10'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_USER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="user_email_subject" class="input-xxlarge form-control"
|
||||
value="<?php echo $this->item->user_email_subject; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_USER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_email_body', $this->item->user_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_USER_EMAIL_BODY_OFFLINE_PAYMENT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_email_body_offline', $this->item->user_email_body_offline, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_ADMIN_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('admin_email_body', $this->item->admin_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THANK_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('thanks_message', $this->item->thanks_message, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THANK_MESSAGE_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('thanks_message_offline', $this->item->thanks_message_offline, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_APPROVED_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="subscription_approved_email_subject" class="input-xxlarge form-control"
|
||||
value="<?php echo $this->item->subscription_approved_email_subject; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_APPROVED_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('subscription_approved_email_body', $this->item->subscription_approved_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_USER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="user_renew_email_subject" class="input-xxlarge form-control"
|
||||
value="<?php echo $this->item->user_renew_email_subject; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_USER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_renew_email_body', $this->item->user_renew_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_USER_EMAIL_BODY_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_renew_email_body_offline', $this->item->user_renew_email_body_offline, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_ADMIN_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('admin_renew_email_body', $this->item->admin_renew_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_USER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_upgrade_email_body', $this->item->user_upgrade_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_USER_EMAIL_BODY_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_upgrade_email_body_offline', $this->item->user_upgrade_email_body_offline, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_ADMIN_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('admin_upgrade_email_body', $this->item->admin_upgrade_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_THANK_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('renew_thanks_message', $this->item->renew_thanks_message, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_THANK_MESSAGE_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('renew_thanks_message_offline', $this->item->renew_thanks_message_offline, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_THANK_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('upgrade_thanks_message', $this->item->upgrade_thanks_message, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_THANK_MESSAGE_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('upgrade_thanks_message_offline', $this->item->upgrade_thanks_message_offline, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_INVOICE_FORMAT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('invoice_layout', $this->item->invoice_layout, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PAGE_TITLE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="input-xxlarge form-control" type="text" name="page_title" id="page_title" maxlength="250"
|
||||
value="<?php echo $this->item->page_title; ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PAGE_HEADING'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="input-xxlarge form-control" type="text" name="page_heading" id="page_heading" maxlength="250"
|
||||
value="<?php echo $this->item->page_heading; ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_META_KEYWORDS'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<textarea rows="5" cols="30" class="input-xxlarge form-control"
|
||||
name="meta_keywords"><?php echo $this->item->meta_keywords; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_META_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<textarea rows="5" cols="30" class="input-xxlarge form-control"
|
||||
name="meta_description"><?php echo $this->item->meta_description; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<fieldset class="adminform">
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_IS_RECURRING_SUBSCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['recurring_subscription']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['recurring_subscription' => '1']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_TRIAL_AMOUNT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" class="form-control" name="trial_amount" value="<?php echo $this->item->trial_amount; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['recurring_subscription' => '1']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_TRIAL_DURATION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" class="form-control input-mini d-inline-block" name="trial_duration" value="<?php echo $this->item->trial_duration > 0 ? $this->item->trial_duration : ''; ?>"/>
|
||||
<?php echo $this->lists['trial_duration_unit']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['recurring_subscription' => '1']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_NUMBER_PAYMENTS'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" class="form-control" name="number_payments" value="<?php echo $this->item->number_payments; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($this->item->number_payments > 0)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::getFieldLabel('last_payment_action', Text::_('OSM_AFTER_LAST_PAYMENT_ACTION'), Text::_('OSM_AFTER_LAST_PAYMENT_ACTION_EXPLAIN')); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $this->lists['last_payment_action']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>" data-showon='<?php echo OSMembershipHelperHtml::renderShowon(['last_payment_action' => '2']); ?>'>
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_EXTEND_DURATION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" class="input-mini" name="extend_duration" value="<?php echo $this->item->extend_duration > 0 ? $this->item->extend_duration : ''; ?>"/>
|
||||
<?php echo $this->lists['extend_duration_unit']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</fieldset>
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<p class="text-error" style="font-size:16px;"><?php echo Text::_('OSM_PLAN_MESSAGES_EXPLAIN'); ?></p>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_FIRST_REMINDER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="first_reminder_email_subject" class="input-xxlarge form-control"
|
||||
value="<?php echo $this->item->first_reminder_email_subject; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_FIRST_REMINDER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('first_reminder_email_body', $this->item->first_reminder_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SECOND_REMINDER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="second_reminder_email_subject" class="input-xxlarge form-control"
|
||||
value="<?php echo $this->item->second_reminder_email_subject; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SECOND_REMINDER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('second_reminder_email_body', $this->item->second_reminder_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THIRD_REMINDER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="third_reminder_email_subject" class="input-xxlarge form-control"
|
||||
value="<?php echo $this->item->third_reminder_email_subject; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THIRD_REMINDER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('third_reminder_email_body', $this->item->third_reminder_email_body, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
?>
|
||||
<fieldset class="adminform">
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SEND_FIRST_REMINDER'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="number" class="form-control input-mini d-inline-block" name="send_first_reminder" value="<?php echo $this->item->send_first_reminder; ?>" /><span><?php echo ' ' . Text::_('OSM_DAYS') . ' ' . $this->lists['send_first_reminder_time']; ?></span><?php echo Text::_('OSM_SUBSCRIPTION_EXPIRED'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SEND_SECOND_REMINDER'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="number" class="form-control input-mini d-inline-block" name="send_second_reminder" value="<?php echo $this->item->send_second_reminder; ?>" /><span><?php echo ' ' . Text::_('OSM_DAYS') . ' ' . $this->lists['send_second_reminder_time']; ?></span><?php echo Text::_('OSM_SUBSCRIPTION_EXPIRED'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SEND_THIRD_REMINDER'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="number" class="form-control input-mini d-inline-block" name="send_third_reminder" value="<?php echo $this->item->send_third_reminder; ?>" /><span><?php echo ' ' . Text::_('OSM_DAYS') . ' ' . $this->lists['send_third_reminder_time']; ?></span><?php echo Text::_('OSM_SUBSCRIPTION_EXPIRED'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($this->item->number_payments > 0)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SEND_SUBSCRIPTION_END'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="number" class="form-control input-mini d-inline-block" name="send_subscription_end" value="<?php echo $this->item->send_subscription_end; ?>" /><span><?php echo ' ' . Text::_('OSM_DAYS') . ' ' . $this->lists['send_subscription_end_time']; ?></span><?php echo Text::_('OSM_SUBSCRIPTION_EXPIRED'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</fieldset>
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Form\Form;
|
||||
|
||||
$form = Form::getInstance('renew_options', JPATH_ADMINISTRATOR . '/components/com_osmembership/view/plan/forms/renew_options.xml');
|
||||
$formData['renew_options'] = [];
|
||||
|
||||
foreach ($this->prices as $renewOption)
|
||||
{
|
||||
$formData['renew_options'][] = [
|
||||
'id' => $renewOption->id,
|
||||
'renew_option_length' => $renewOption->renew_option_length,
|
||||
'renew_option_length_unit' => $renewOption->renew_option_length_unit,
|
||||
'price' => $renewOption->price,
|
||||
];
|
||||
}
|
||||
|
||||
$form->bind($formData);
|
||||
|
||||
foreach ($form->getFieldset() as $field)
|
||||
{
|
||||
echo $field->input;
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Form\Form;
|
||||
|
||||
$form = Form::getInstance('renewal_discounts', JPATH_ADMINISTRATOR . '/components/com_osmembership/view/plan/forms/renewal_discounts.xml');
|
||||
$formData['renewal_discounts'] = [];
|
||||
|
||||
foreach ($this->renewalDiscounts as $renewalDiscount)
|
||||
{
|
||||
$formData['renewal_discounts'][] = [
|
||||
'id' => $renewalDiscount->id,
|
||||
'number_days' => $renewalDiscount->number_days,
|
||||
'discount_type' => $renewalDiscount->discount_type,
|
||||
'discount_amount' => $renewalDiscount->discount_amount,
|
||||
];
|
||||
}
|
||||
|
||||
$form->bind($formData);
|
||||
|
||||
foreach ($form->getFieldset() as $field)
|
||||
{
|
||||
echo $field->input;
|
||||
}
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
$rootUri = Uri::root(true);
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
|
||||
echo HTMLHelper::_('bootstrap.startTabSet', 'plan-translation', ['active' => 'translation-page-' . $this->languages[0]->sef, 'recall' => true]);
|
||||
|
||||
foreach ($this->languages as $language)
|
||||
{
|
||||
$sef = $language->sef;
|
||||
echo HTMLHelper::_('bootstrap.addTab', 'plan-translation', 'translation-page-' . $sef, $language->title . ' <img src="' . $rootUri . '/media/mod_languages/images/' . $language->image . '.gif" />');
|
||||
?>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_TITLE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-xlarge" type="text" name="title_<?php echo $sef; ?>" id="title_<?php echo $sef; ?>" maxlength="250" value="<?php echo $this->item->{'title_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_ALIAS'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-xlarge" type="text" name="alias_<?php echo $sef; ?>" id="title_<?php echo $sef; ?>" maxlength="250" value="<?php echo $this->item->{'alias_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SHORT_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('short_description_' . $sef, $this->item->{'short_description_' . $sef}, '100%', '250', '75', '10') ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('description_' . $sef, $this->item->{'description_' . $sef}, '100%', '250', '75', '10') ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PAGE_TITLE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-xlarge" type="text" name="page_title_<?php echo $sef; ?>" id="page_title_<?php echo $sef; ?>" maxlength="250" value="<?php echo $this->item->{'page_title_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PAGE_HEADING'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input class="form-control input-xlarge" type="text" name="page_heading_<?php echo $sef; ?>" id="page_heading_<?php echo $sef; ?>" maxlength="250" value="<?php echo $this->item->{'page_heading_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_META_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<textarea rows="5" cols="30" class="input-lage" name="meta_description_<?php echo $sef; ?>"><?php echo $this->item->{'meta_description_' . $sef}; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_META_KEYWORDS'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<textarea rows="5" cols="30" class="input-lage" name="meta_keywords_<?php echo $sef; ?>"><?php echo $this->item->{'meta_keywords_' . $sef}; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_META_DESCRIPTION'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<textarea rows="5" cols="30" class="input-lage" name="meta_description_<?php echo $sef; ?>"><?php echo $this->item->{'meta_description_' . $sef}; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_PLAN_SUBSCRIPTION_FORM_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('subscription_form_message_' . $sef, $this->item->{'subscription_form_message_' . $sef}, '100%', '250', '75', '10') ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_USER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="user_email_subject_<?php echo $sef; ?>" class="form-control" value="<?php echo $this->item->{'user_email_subject_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_USER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_email_body_' . $sef, $this->item->{'user_email_body_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_USER_EMAIL_BODY_OFFLINE_PAYMENT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_email_body_offline_' . $sef, $this->item->{'user_email_body_offline_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THANK_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('thanks_message_' . $sef, $this->item->{'thanks_message_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_THANK_MESSAGE_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('thanks_message_offline_' . $sef, $this->item->{'thanks_message_offline_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_APPROVED_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="subscription_approved_email_subject_<?php echo $sef; ?>" class="form-control" value="<?php echo $this->item->{'subscription_approved_email_subject_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_SUBSCRIPTION_APPROVED_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('subscription_approved_email_body_' . $sef, $this->item->{'subscription_approved_email_body_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_USER_EMAIL_SUBJECT'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<input type="text" name="user_renew_email_subject_<?php echo $sef; ?>" class="form-control" value="<?php echo $this->item->{'user_renew_email_subject_' . $sef}; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_USER_EMAIL_BODY'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('user_renew_email_body_' . $sef, $this->item->{'user_renew_email_body_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_THANK_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('renew_thanks_message_' . $sef, $this->item->{'renew_thanks_message_' . $sef}, '100%', '250', '75', '8') ;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_RENEW_THANK_MESSAGE_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('renew_thanks_message_offline_' . $sef, $this->item->{'renew_thanks_message_offline_' . $sef}, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_THANK_MESSAGE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('upgrade_thanks_message_' . $sef, $this->item->{'upgrade_thanks_message_' . $sef}, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $controlGroupClass; ?>">
|
||||
<div class="<?php echo $controlLabelClass; ?>">
|
||||
<?php echo Text::_('OSM_UPGRADE_THANK_MESSAGE_OFFLINE'); ?>
|
||||
</div>
|
||||
<div class="<?php echo $controlsClass; ?>">
|
||||
<?php echo $editor->display('upgrade_thanks_message_offline_' . $sef, $this->item->{'upgrade_thanks_message_offline_' . $sef}, '100%', '250', '75', '8'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo HTMLHelper::_('bootstrap.endTab');
|
||||
}
|
||||
|
||||
echo HTMLHelper::_('bootstrap.endTabSet');
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Form\Form;
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$rowFluidClasss = $bootstrapHelper->getClassMapping('row-fluid');
|
||||
$controlGroupClass = $bootstrapHelper->getClassMapping('control-group');
|
||||
$controlLabelClass = $bootstrapHelper->getClassMapping('control-label');
|
||||
$controlsClass = $bootstrapHelper->getClassMapping('controls');
|
||||
|
||||
$form = Form::getInstance('upgrade_options', JPATH_ADMINISTRATOR . '/components/com_osmembership/view/plan/forms/upgrade_options.xml');
|
||||
$formData['upgrade_options'] = [];
|
||||
|
||||
foreach ($this->upgradeRules as $upgradeOption)
|
||||
{
|
||||
$formData['upgrade_options'][] = [
|
||||
'id' => $upgradeOption->id,
|
||||
'to_plan_id' => $upgradeOption->to_plan_id,
|
||||
'price' => $upgradeOption->price,
|
||||
'upgrade_prorated' => $upgradeOption->upgrade_prorated,
|
||||
'published' => $upgradeOption->published,
|
||||
];
|
||||
}
|
||||
|
||||
$form->bind($formData);
|
||||
|
||||
foreach ($form->getFieldset() as $field)
|
||||
{
|
||||
echo $field->input;
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,238 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Toolbar\Toolbar;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
HTMLHelper::_('formbehavior.chosen', 'select');
|
||||
|
||||
$bootstrapHelper = OSMembershipHelperBootstrap::getInstance();
|
||||
$centerClass = $bootstrapHelper->getClassMapping('center');
|
||||
$cols = 10;
|
||||
$config = OSMembershipHelper::getConfig();
|
||||
?>
|
||||
<div id="osm-manage-plans" class="osm-container osm-container-j4">
|
||||
<?php
|
||||
if ($this->params->get('show_page_heading', 1))
|
||||
{
|
||||
if ($this->input->getInt('hmvc_call'))
|
||||
{
|
||||
$hTag = 'h2';
|
||||
}
|
||||
else
|
||||
{
|
||||
$hTag = 'h1';
|
||||
}
|
||||
?>
|
||||
<<?php echo $hTag; ?> class="osm-heading"><?php echo Text::_('OSM_MANAGE_PLANS'); ?></<?php echo $hTag; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (OSMembershipHelper::isValidMessage($this->params->get('intro_text')))
|
||||
{
|
||||
?>
|
||||
<div class="osm-description osm-page-intro-text <?php echo $this->bootstrapHelper->getClassMapping('clearfix'); ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $this->params->get('intro_text')); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="btn-toolbar" id="btn-toolbar">
|
||||
<?php echo Toolbar::getInstance('toolbar')->render(); ?>
|
||||
</div>
|
||||
<form action="<?php echo Route::_('index.php?option=com_osmembership&view=mplans&Itemid=' . $this->Itemid, false); ?>" method="post" name="adminForm" id="adminForm">
|
||||
<div class="filters btn-toolbar clearfix mt-2 mb-2">
|
||||
<?php echo $this->loadTemplate('search_bar'); ?>
|
||||
</div>
|
||||
<table class="<?php echo $bootstrapHelper->getClassMapping('table table-striped table-bordered table-hover'); ?>">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="20">
|
||||
<?php echo HTMLHelper::_('grid.checkall'); ?>
|
||||
</th>
|
||||
<th class="title">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('OSM_TITLE'), 'tbl.title', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
<?php
|
||||
if ($this->showCategory)
|
||||
{
|
||||
$cols++;
|
||||
?>
|
||||
<th class="title">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('OSM_CATEGORY'), 'b.title', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($this->showThumbnail)
|
||||
{
|
||||
$cols++;
|
||||
?>
|
||||
<th class="title" width="10%">
|
||||
<?php echo Text::_('OSM_THUMB'); ?>
|
||||
</th>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<th class="title" width="8%">
|
||||
<?php echo Text::_('OSM_LENGTH'); ?>
|
||||
</th>
|
||||
<th class="center" width="8%">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('OSM_RECURRING'), 'tbl.recurring_subscription', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
<th class="title" width="8%">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('OSM_PRICE'), 'tbl.price', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
<th class="title center" width="12%">
|
||||
<?php echo Text::_('OSM_TOTAL_SUBSCRIBERS'); ?>
|
||||
</th>
|
||||
<th class="title center" width="12%">
|
||||
<?php echo Text::_('OSM_ACTIVE_SUBSCRIBERS'); ?>
|
||||
</th>
|
||||
<th width="5%">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('JGRID_HEADING_ACCESS'), 'tbl.access', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
<th width="5%">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('OSM_PUBLISHED'), 'tbl.published', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
<th width="2%">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', Text::_('OSM_ID'), 'tbl.id', $this->state->filter_order_Dir, $this->state->filter_order); ?>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="<?php echo $cols; ?>">
|
||||
<?php echo $this->pagination->getListFooter(); ?>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<?php
|
||||
$k = 0;
|
||||
for ($i = 0, $n = count($this->items); $i < $n; $i++)
|
||||
{
|
||||
$row = $this->items[$i];
|
||||
$link = Route::_('index.php?option=com_osmembership&task=mplan.edit&id=' . $row->id . '&Itemid=' . $this->Itemid, false);
|
||||
$checked = HTMLHelper::_('grid.id', $i, $row->id);
|
||||
$published = HTMLHelper::_('jgrid.published', $row->published, $i, 'mplan.');
|
||||
$symbol = $row->currency_symbol ?: $row->currency;
|
||||
?>
|
||||
<tr class="<?php echo "row$k"; ?>">
|
||||
<td>
|
||||
<?php echo $checked; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
if (OSMembershipHelperAcl::canEditPlan($row->id))
|
||||
{
|
||||
?>
|
||||
<a href="<?php echo $link; ?>"><?php echo $row->title ; ?></a>
|
||||
<?php
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $row->title;
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<?php
|
||||
if ($this->showCategory)
|
||||
{
|
||||
?>
|
||||
<td><?php echo $row->category_title; ?></td>
|
||||
<?php
|
||||
}
|
||||
if ($this->showThumbnail)
|
||||
{
|
||||
?>
|
||||
<td class="center">
|
||||
<?php
|
||||
if ($row->thumb)
|
||||
{
|
||||
?>
|
||||
<a href="<?php echo Uri::root() . 'media/com_osmembership/' . $row->thumb ; ?>" class="modal"><img src="<?php echo Uri::root() . '/media/com_osmembership/' . $row->thumb ; ?>" /></a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<td>
|
||||
<?php
|
||||
if ($row->lifetime_membership)
|
||||
{
|
||||
echo Text::_('OSM_LIFETIME');
|
||||
}
|
||||
else
|
||||
{
|
||||
echo OSMembershipHelperSubscription::getDurationText($row->subscription_length, $row->subscription_length_unit);
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="center">
|
||||
<?php echo $row->recurring_subscription ? Text::_('JYES') : Text::_('JNO'); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
if ($row->price > 0)
|
||||
{
|
||||
echo OSMembershipHelper::formatCurrency($row->price, $config, $symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo Text::_('OSM_FREE');
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="center">
|
||||
<?php echo OSMembershipHelper::countSubscribers($row->id); ?>
|
||||
</td>
|
||||
<td class="center">
|
||||
<?php echo OSMembershipHelper::countSubscribers($row->id, 1); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $row->access_level; ?>
|
||||
</td>
|
||||
<td class="center">
|
||||
<?php
|
||||
if (OSMembershipHelperAcl::canChangePlanState($row->id))
|
||||
{
|
||||
echo $published;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $row->published ? Text::_('JYES') : Text::_('JNO');
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="center">
|
||||
<?php echo $row->id; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
$k = 1 - $k;
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<input type="hidden" name="task" value="" />
|
||||
<input type="hidden" name="boxchecked" value="0" />
|
||||
<input type="hidden" name="filter_order" value="<?php echo $this->state->filter_order; ?>" />
|
||||
<input type="hidden" name="filter_order_Dir" value="<?php echo $this->state->filter_order_Dir; ?>" />
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$pullLeftClass = $this->bootstrapHelper->getClassMapping('pull-left');
|
||||
?>
|
||||
<div class="filter-search btn-group <?php echo $pullLeftClass; ?>">
|
||||
<div class="input-group">
|
||||
<label for="filter_search" class="sr-only"><?php echo Text::_('OSM_FILTER_SEARCH_PLANS_DESC');?></label>
|
||||
<input type="text" name="filter_search" id="filter_search" placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>" value="<?php echo $this->escape($this->state->filter_search); ?>" class="hasTooltip form-control" title="<?php echo HTMLHelper::tooltipText('OSM_SEARCH_PLANS_DESC'); ?>" />
|
||||
<span class="input-group-append">
|
||||
<button type="submit" class="btn hasTooltip" title="<?php echo HTMLHelper::tooltipText('JSEARCH_FILTER_SUBMIT'); ?>"><span class="fa fa-search"></span></button>
|
||||
<button type="button" class="btn hasTooltip" title="<?php echo HTMLHelper::tooltipText('JSEARCH_FILTER_CLEAR'); ?>" onclick="document.getElementById('filter_search').value='';this.form.submit();"><span class="fa fa-remove"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group <?php echo $pullLeftClass; ?> ml-2">
|
||||
<?php
|
||||
if (isset($this->lists['filter_category_id']))
|
||||
{
|
||||
echo $this->lists['filter_category_id'];
|
||||
}
|
||||
|
||||
echo $this->lists['filter_state'];
|
||||
echo $this->pagination->getLimitBox();
|
||||
?>
|
||||
</div>
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$pullLeftClass = $this->bootstrapHelper->getClassMapping('pull-left');
|
||||
?>
|
||||
<div class="filter-search btn-group <?php echo $pullLeftClass; ?>">
|
||||
<label for="filter_search" class="element-invisible sr-only"><?php echo Text::_('OSM_FILTER_SEARCH_PLANS_DESC');?></label>
|
||||
<input type="text" name="filter_search" id="filter_search" placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>" value="<?php echo $this->escape($this->state->filter_search); ?>" class="hasTooltip input-medium" title="<?php echo HTMLHelper::tooltipText('OSM_SEARCH_PLANS_DESC'); ?>" />
|
||||
</div>
|
||||
<div class="btn-group <?php echo $pullLeftClass; ?>">
|
||||
<button type="submit" class="btn btn-primary hasTooltip" title="<?php echo HTMLHelper::tooltipText('JSEARCH_FILTER_SUBMIT'); ?>"><span class="<?php echo $this->bootstrapHelper->getClassMapping('icon-search'); ?>"></span></button>
|
||||
<button type="button" class="btn btn-primary hasTooltip" title="<?php echo HTMLHelper::tooltipText('JSEARCH_FILTER_CLEAR'); ?>" onclick="document.getElementById('filter_search').value='';this.form.submit();"><span class="<?php echo $this->bootstrapHelper->getClassMapping('icon-remove'); ?>"></span></button>
|
||||
</div>
|
||||
<div class="btn-group <?php echo $pullLeftClass; ?>">
|
||||
<?php
|
||||
if (isset($this->lists['filter_category_id']))
|
||||
{
|
||||
echo $this->lists['filter_category_id'];
|
||||
}
|
||||
|
||||
echo $this->lists['filter_state'];
|
||||
|
||||
echo $this->pagination->getLimitBox();
|
||||
?>
|
||||
</div>
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,176 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
$item = $this->item;
|
||||
|
||||
$clearfixClass = $this->bootstrapHelper->getClassMapping('clearfix');
|
||||
|
||||
if ($item->thumb)
|
||||
{
|
||||
$imgSrc = Uri::base() . 'media/com_osmembership/' . $item->thumb;
|
||||
}
|
||||
|
||||
if ($this->config->use_https)
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $this->Itemid), false, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpUrl = Route::_(OSMembershipHelperRoute::getSignupRoute($item->id, $this->Itemid));
|
||||
}
|
||||
|
||||
$subscribedPlanIds = OSMembershipHelperSubscription::getSubscribedPlans();
|
||||
|
||||
$showPlanInformation = $this->params->get('show_plan_information', 1);
|
||||
$planInformationPosition = $this->params->get('plan_information_position', 0);
|
||||
|
||||
if ($showPlanInformation && $planInformationPosition == 0)
|
||||
{
|
||||
$leftClass = $this->bootstrapHelper->getClassMapping('span7');
|
||||
$rightClass = $this->bootstrapHelper->getClassMapping('span5');
|
||||
}
|
||||
else
|
||||
{
|
||||
$leftClass = $this->bootstrapHelper->getClassMapping('clearfix');
|
||||
$rightClass = $this->bootstrapHelper->getClassMapping('clearfix');
|
||||
}
|
||||
?>
|
||||
<div id="osm-plan-item" class="osm-container">
|
||||
<div class="osm-item-heading-box <?php echo $clearfixClass; ?>">
|
||||
<h1 class="osm-page-title">
|
||||
<?php echo $this->params->get('page_heading'); ?>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="osm-item-description <?php echo $clearfixClass; ?>">
|
||||
<div class="<?php echo $this->bootstrapHelper->getClassMapping('row-fluid clearfix'); ?>">
|
||||
<?php
|
||||
if ($showPlanInformation && $planInformationPosition == 1)
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $rightClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/plan_information.php', ['item' => $item]); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div class="osm-description-details <?php echo $leftClass; ?> ">
|
||||
<?php
|
||||
if ($item->thumb)
|
||||
{
|
||||
?>
|
||||
<img src="<?php echo $imgSrc; ?>" alt="<?php echo $item->title; ?>" class="osm-thumb-left img-polaroid"/>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($item->description)
|
||||
{
|
||||
echo $item->description;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $item->short_description;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
if ($showPlanInformation && in_array($planInformationPosition, [0, 2]))
|
||||
{
|
||||
?>
|
||||
<div class="<?php echo $rightClass; ?>">
|
||||
<?php echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/plan_information.php', ['item' => $item]); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if (count($this->renewOptions) || count($this->upgradeRules))
|
||||
{
|
||||
echo $this->loadTemplate('renew_upgrade');
|
||||
}
|
||||
?>
|
||||
<div class="osm-taskbar <?php echo $clearfixClass; ?>">
|
||||
<ul>
|
||||
<?php
|
||||
$actions = OSMembershipHelperSubscription::getAllowedActions($item);
|
||||
|
||||
if (count($actions))
|
||||
{
|
||||
$language = Factory::getApplication()->getLanguage();
|
||||
|
||||
if (in_array('subscribe', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_SIGNUP_PLAN_' . $item->id))
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$signUpLanguageItem = 'OSM_SIGNUP';
|
||||
}
|
||||
|
||||
if ($language->hasKey('OSM_RENEW_PLAN_' . $item->id))
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$renewLanguageItem = 'OSM_RENEW';
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $signUpUrl; ?>" class="<?php echo $this->bootstrapHelper->getClassMapping('btn btn-primary'); ?>">
|
||||
<?php echo in_array($item->id, $subscribedPlanIds) ? Text::_($renewLanguageItem) : Text::_($signUpLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (in_array('upgrade', $actions))
|
||||
{
|
||||
if ($language->hasKey('OSM_UPGRADE_PLAN_' . $item->id))
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE_PLAN_' . $item->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeLanguageItem = 'OSM_UPGRADE';
|
||||
}
|
||||
|
||||
if (count($item->upgrade_rules) > 1)
|
||||
{
|
||||
$link = Route::_('index.php?option=com_osmembership&view=upgrademembership&to_plan_id=' . $item->id . '&Itemid=' . OSMembershipHelperRoute::findView('upgrademembership', $this->Itemid));
|
||||
}
|
||||
else
|
||||
{
|
||||
$upgradeOptionId = $item->upgrade_rules[0]->id;
|
||||
$link = Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&upgrade_option_id=' . $upgradeOptionId . '&Itemid=' . $this->Itemid);
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<a href="<?php echo $link; ?>" class="<?php echo $this->bootstrapHelper->getClassMapping('btn btn-primary'); ?>">
|
||||
<?php echo Text::_($upgradeLanguageItem); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
?>
|
||||
<div class="<?php echo $this->bootstrapHelper->getClassMapping('row-fluid clearfix'); ?>">
|
||||
<?php
|
||||
if (count($this->renewOptions))
|
||||
{
|
||||
?>
|
||||
<form action="<?php echo Route::_('index.php?option=com_osmembership&task=register.process_renew_membership&Itemid=' . $this->Itemid, false, $ssl); ?>" method="post" name="osm_form_renew" id="osm_form_renew" autocomplete="off" class="<?php echo $this->bootstrapHelper->getClassMapping('form form-horizontal'); ?>">
|
||||
<h2 class="osm-form-heading"><?php echo Text::_('OSM_RENEW_MEMBERSHIP'); ?></h2>
|
||||
<?php echo $this->loadCommonLayout('common/tmpl/renew_options.php');?>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (count($this->upgradeRules))
|
||||
{
|
||||
?>
|
||||
<form action="<?php echo Route::_('index.php?option=com_osmembership&task=register.process_upgrade_membership&Itemid=' . $this->Itemid, false, $ssl); ?>" method="post" name="osm_form_update_membership" id="osm_form_update_membership" autocomplete="off" class="<?php echo $this->bootstrapHelper->getClassMapping('form form-horizontal'); ?>">
|
||||
<h2 class="osm-form-heading"><?php echo Text::_('OSM_UPGRADE_MEMBERSHIP'); ?></h2>
|
||||
<?php
|
||||
echo $this->loadCommonLayout('common/tmpl/upgrade_options.php');
|
||||
?>
|
||||
<div class="form-actions">
|
||||
<input type="submit" class="<?php echo $this->bootstrapHelper->getClassMapping('btn btn-primary'); ?>" value="<?php echo Text::_('OSM_PROCESS_UPGRADE'); ?>"/>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
?>
|
||||
<div id="osm-plans-list-columns" class="osm-container osm-container-j4">
|
||||
<?php
|
||||
if ($this->params->get('show_page_heading', 1))
|
||||
{
|
||||
if ($this->category)
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: $this->category->title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: Text::_('OSM_SUBSCRIPTION_PLANS');
|
||||
}
|
||||
|
||||
if ($this->input->getInt('hmvc_call'))
|
||||
{
|
||||
$hTag = 'h2';
|
||||
}
|
||||
else
|
||||
{
|
||||
$hTag = 'h1';
|
||||
}
|
||||
?>
|
||||
<<?php echo $hTag; ?> class="osm-page-title"><?php echo $pageHeading; ?></<?php echo $hTag; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!empty($this->category->description))
|
||||
{
|
||||
$description = $this->category->description;
|
||||
}
|
||||
elseif (OSMembershipHelper::isValidMessage($this->params->get('intro_text')))
|
||||
{
|
||||
$description = $this->params->get('intro_text');
|
||||
}
|
||||
else
|
||||
{
|
||||
$description = '';
|
||||
}
|
||||
|
||||
if ($description)
|
||||
{
|
||||
?>
|
||||
<div class="osm-description osm-page-intro-text <?php echo $this->bootstrapHelper->getClassMapping('clearfix'); ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $description); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (count($this->categories))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/categories.php', ['items' => $this->categories, 'categoryId' => $this->categoryId, 'config' => $this->config, 'Itemid' => $this->Itemid]);
|
||||
}
|
||||
|
||||
if (count($this->items))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/columns_plans.php', ['items' => $this->items, 'input' => $this->input, 'config' => $this->config, 'Itemid' => $this->Itemid, 'categoryId' => $this->categoryId, 'bootstrapHelper' => $this->bootstrapHelper, 'params' => $this->params]);
|
||||
}
|
||||
|
||||
if (!$this->input->getInt('hmvc_call') && ($this->pagination->total > $this->pagination->limit))
|
||||
{
|
||||
?>
|
||||
<div class="pagination">
|
||||
<?php echo $this->pagination->getPagesLinks(); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
defined('_JEXEC') or die ;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
?>
|
||||
<div id="osm-plans-list-default" class="osm-container osm-container-j4">
|
||||
<?php
|
||||
if ($this->params->get('show_page_heading', 1))
|
||||
{
|
||||
if ($this->category)
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: $this->category->title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: Text::_('OSM_SUBSCRIPTION_PLANS');
|
||||
}
|
||||
|
||||
if ($this->input->getInt('hmvc_call'))
|
||||
{
|
||||
$hTag = 'h2';
|
||||
}
|
||||
else
|
||||
{
|
||||
$hTag = 'h1';
|
||||
}
|
||||
?>
|
||||
<<?php echo $hTag; ?> class="osm-page-title"><?php echo $pageHeading; ?></<?php echo $hTag; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!empty($this->category->description))
|
||||
{
|
||||
$description = $this->category->description;
|
||||
}
|
||||
elseif (OSMembershipHelper::isValidMessage($this->params->get('intro_text')))
|
||||
{
|
||||
$description = $this->params->get('intro_text');
|
||||
}
|
||||
else
|
||||
{
|
||||
$description = '';
|
||||
}
|
||||
|
||||
if ($description)
|
||||
{
|
||||
?>
|
||||
<div class="osm-description osm-page-intro-text <?php echo $this->bootstrapHelper->getClassMapping('clearfix'); ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $description); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (count($this->categories))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/categories.php', ['items' => $this->categories, 'categoryId' => $this->categoryId, 'config' => $this->config, 'Itemid' => $this->Itemid]);
|
||||
}
|
||||
|
||||
if (count($this->items))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/default_plans.php', ['items' => $this->items, 'input' => $this->input, 'config' => $this->config, 'Itemid' => $this->Itemid, 'categoryId' => $this->categoryId, 'bootstrapHelper' => $this->bootstrapHelper, 'params' => $this->params]);
|
||||
}
|
||||
|
||||
if (!$this->input->getInt('hmvc_call') && ($this->pagination->total > $this->pagination->limit))
|
||||
{
|
||||
?>
|
||||
<div class="pagination">
|
||||
<?php echo $this->pagination->getPagesLinks(); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$categoryId = $this->category ? $this->category->id : 0;
|
||||
?>
|
||||
<div id="osm-plans-list-columns" class="osm-container osm-container-j4 osm-pricingtable-container<?php echo $categoryId; ?>">
|
||||
<?php
|
||||
if ($this->params->get('show_page_heading', 1))
|
||||
{
|
||||
if ($this->category)
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: $this->category->title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: Text::_('OSM_SUBSCRIPTION_PLANS');
|
||||
}
|
||||
|
||||
if ($this->input->getInt('hmvc_call'))
|
||||
{
|
||||
$hTag = 'h2';
|
||||
}
|
||||
else
|
||||
{
|
||||
$hTag = 'h1';
|
||||
}
|
||||
?>
|
||||
<<?php echo $hTag; ?> class="osm-page-title"><?php echo $pageHeading; ?></<?php echo $hTag; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!empty($this->category->description))
|
||||
{
|
||||
$description = $this->category->description;
|
||||
}
|
||||
elseif (OSMembershipHelper::isValidMessage($this->params->get('intro_text')))
|
||||
{
|
||||
$description = $this->params->get('intro_text');
|
||||
}
|
||||
else
|
||||
{
|
||||
$description = '';
|
||||
}
|
||||
|
||||
if ($description)
|
||||
{
|
||||
?>
|
||||
<div class="osm-description osm-page-intro-text <?php echo $this->bootstrapHelper->getClassMapping('clearfix'); ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $description); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (count($this->categories))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/categories.php', ['items' => $this->categories, 'categoryId' => $this->categoryId, 'config' => $this->config, 'Itemid' => $this->Itemid]);
|
||||
}
|
||||
|
||||
if (count($this->items))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/pricingtable_plans.php', ['items' => $this->items, 'input' => $this->input, 'config' => $this->config, 'Itemid' => $this->Itemid, 'categoryId' => $this->categoryId, 'bootstrapHelper' => $this->bootstrapHelper, 'params' => $this->params]);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$categoryId = $this->category ? $this->category->id : 0;
|
||||
?>
|
||||
<div id="osm-plans-list-pricing-table-circle" class="osm-container osm-container-j4 osm-pricingtable-container<?php echo $categoryId; ?>">
|
||||
<?php
|
||||
if ($this->params->get('show_page_heading', 1))
|
||||
{
|
||||
if ($this->category)
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: $this->category->title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: Text::_('OSM_SUBSCRIPTION_PLANS');
|
||||
}
|
||||
|
||||
if ($this->input->getInt('hmvc_call'))
|
||||
{
|
||||
$hTag = 'h2';
|
||||
}
|
||||
else
|
||||
{
|
||||
$hTag = 'h1';
|
||||
}
|
||||
?>
|
||||
<<?php echo $hTag; ?> class="osm-page-title"><?php echo $pageHeading; ?></<?php echo $hTag; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!empty($this->category->description))
|
||||
{
|
||||
$description = $this->category->description;
|
||||
}
|
||||
elseif (OSMembershipHelper::isValidMessage($this->params->get('intro_text')))
|
||||
{
|
||||
$description = $this->params->get('intro_text');
|
||||
}
|
||||
else
|
||||
{
|
||||
$description = '';
|
||||
}
|
||||
|
||||
if ($description)
|
||||
{
|
||||
?>
|
||||
<div class="osm-description osm-page-intro-text <?php echo $this->bootstrapHelper->getClassMapping('clearfix'); ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $description); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (count($this->categories))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/categories.php', ['items' => $this->categories, 'categoryId' => $this->categoryId, 'config' => $this->config, 'Itemid' => $this->Itemid]);
|
||||
}
|
||||
|
||||
if (count($this->items))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/pricingtable_circle_plans.php', ['items' => $this->items, 'input' => $this->input, 'config' => $this->config, 'Itemid' => $this->Itemid, 'categoryId' => $this->categoryId, 'bootstrapHelper' => $this->bootstrapHelper, 'params' => $this->params]);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla
|
||||
* @subpackage Membership Pro
|
||||
* @author Tuan Pham Ngoc
|
||||
* @copyright Copyright (C) 2012 - 2025 Ossolution Team
|
||||
* @license GNU/GPL, see LICENSE.php
|
||||
*/
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
$categoryId = $this->category ? $this->category->id : 0;
|
||||
?>
|
||||
<div id="osm-plans-list-pricing-table-flat" class="osm-container osm-container-j4 osm-pricingtable-container<?php echo $categoryId; ?>">
|
||||
<?php
|
||||
if ($this->params->get('show_page_heading', 1))
|
||||
{
|
||||
if ($this->category)
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: $this->category->title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pageHeading = $this->params->get('page_heading') ?: Text::_('OSM_SUBSCRIPTION_PLANS');
|
||||
}
|
||||
|
||||
if ($this->input->getInt('hmvc_call'))
|
||||
{
|
||||
$hTag = 'h2';
|
||||
}
|
||||
else
|
||||
{
|
||||
$hTag = 'h1';
|
||||
}
|
||||
?>
|
||||
<<?php echo $hTag; ?> class="osm-page-title"><?php echo $pageHeading; ?></<?php echo $hTag; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!empty($this->category->description))
|
||||
{
|
||||
$description = $this->category->description;
|
||||
}
|
||||
elseif (OSMembershipHelper::isValidMessage($this->params->get('intro_text')))
|
||||
{
|
||||
$description = $this->params->get('intro_text');
|
||||
}
|
||||
else
|
||||
{
|
||||
$description = '';
|
||||
}
|
||||
|
||||
if ($description)
|
||||
{
|
||||
?>
|
||||
<div class="osm-description osm-page-intro-text <?php echo $this->bootstrapHelper->getClassMapping('clearfix'); ?>">
|
||||
<?php echo HTMLHelper::_('content.prepare', $description); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (count($this->categories))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/categories.php', ['items' => $this->categories, 'categoryId' => $this->categoryId, 'config' => $this->config, 'Itemid' => $this->Itemid]);
|
||||
}
|
||||
|
||||
if (count($this->items))
|
||||
{
|
||||
echo OSMembershipHelperHtml::loadCommonLayout('common/tmpl/pricingtable_flat_plans.php', ['items' => $this->items, 'input' => $this->input, 'config' => $this->config, 'Itemid' => $this->Itemid, 'categoryId' => $this->categoryId, 'bootstrapHelper' => $this->bootstrapHelper, 'params' => $this->params]);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
\Joomla\CMS\HTML\HTMLHelper::_('bootstrap.dropdown');
|
||||
|
||||
vmJsApi::cssSite();
|
||||
|
||||
$data = $cart->prepareAjaxData(true);
|
||||
$view = vRequest::getCmd('view');
|
||||
?>
|
||||
|
||||
<div class="vmCartModule row <?php echo $params->get('moduleclass_sfx'); ?>">
|
||||
<div class="col-12 mb-2">
|
||||
<p class="total_products px-2 py-1 bg-light">
|
||||
<?php echo $data->totalProductTxt ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php if ($show_product_list) : ?>
|
||||
<div class="hiddencontainer d-none" id="hiddencontainer">
|
||||
<div class="vmcontainer">
|
||||
<div class="product_row row align-items-center pb-2 mb-2">
|
||||
<div class="product_image col-3">
|
||||
<div class="image image img-thumbnail"></div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span class="quantity"></span>
|
||||
x
|
||||
<span class="product_name"></span>
|
||||
<div class="customProductData col-12 mt-1 small"></div>
|
||||
</div>
|
||||
<?php if ($show_price and $currencyDisplay->_priceConfig['salesPrice'][0]) : ?>
|
||||
<div class="col-3 text-end">
|
||||
<span class="subtotal_with_tax"></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-12 mt-3">
|
||||
<div class="border-bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vmcontainer vm_cart_products container small">
|
||||
<?php foreach ($data->products as $product) : ?>
|
||||
<div class="product_row row align-items-center pb-2 mb-2">
|
||||
<div class="product_image col-3">
|
||||
<?php if ( VmConfig::get('oncheckout_show_images')) : ?>
|
||||
<div class="image img-thumbnail"><?php echo $product['image']; ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<span class="quantity">
|
||||
<?php echo $product['quantity'] ?>
|
||||
</span>
|
||||
x
|
||||
<span class="product_name">
|
||||
<?php echo $product['product_name'] ?>
|
||||
</span>
|
||||
<div class="customProductData col-12 mt-1 small">
|
||||
<?php echo $product['customProductData'] ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($show_price and $currencyDisplay->_priceConfig['salesPrice'][0]) : ?>
|
||||
<div class="col-3 text-end text-nowrap">
|
||||
<span class="subtotal_with_tax">
|
||||
<?php echo $product['subtotal_with_tax'] ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-12 mt-3">
|
||||
<div class="border-bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="show_cart_m d-flex align-items-center container">
|
||||
<a class="btn btn-secondary btn-sm show-cart me-auto" href="<?php echo $data->cart_show_link; ?>" rel="nofollow">
|
||||
<?php echo vmText::_('COM_VIRTUEMART_CART_SHOW'); ?>
|
||||
</a>
|
||||
<span class="total small">
|
||||
<?php echo !empty($data->products) ? $data->billTotal : ''; ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($view != 'cart' and $view != 'user') : ?>
|
||||
<div class="payments-signin-button"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<noscript>
|
||||
<?php echo vmText::_('MOD_VIRTUEMART_CART_AJAX_CART_PLZ_JAVASCRIPT') ?>
|
||||
</noscript>
|
||||
</div>
|
||||
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage Templates.vmbasic
|
||||
*
|
||||
* @copyright (C) 2024 Spiros Petrakis
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
\Joomla\CMS\HTML\HTMLHelper::_('bootstrap.dropdown');
|
||||
|
||||
vmJsApi::cssSite();
|
||||
|
||||
$data = $cart->prepareAjaxData(true);
|
||||
$view = vRequest::getCmd('view');
|
||||
?>
|
||||
|
||||
<div class="vmCartModule <?php echo $params->get('moduleclass_sfx'); ?> dropdown">
|
||||
<button class="btn btn-link btn-sm p-0 dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-cart3" viewBox="0 0 16 16">
|
||||
<path d="M0 1.5A.5.5 0 0 1 .5 1H2a.5.5 0 0 1 .485.379L2.89 3H14.5a.5.5 0 0 1 .49.598l-1 5a.5.5 0 0 1-.465.401l-9.397.472L4.415 11H13a.5.5 0 0 1 0 1H4a.5.5 0 0 1-.491-.408L2.01 3.607 1.61 2H.5a.5.5 0 0 1-.5-.5M3.102 4l.84 4.479 9.144-.459L13.89 4zM5 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4m7 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4m-7 1a1 1 0 1 1 0 2 1 1 0 0 1 0-2m7 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2"/>
|
||||
</svg>
|
||||
|
||||
<span class="total_products ms-2">
|
||||
<?php echo $data->totalProductTxt ?>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<?php if ($show_product_list) : ?>
|
||||
<div class="hiddencontainer d-none" id="hiddencontainer">
|
||||
<div class="vmcontainer">
|
||||
<div class="product_row row align-items-center pb-2 mb-2 border-bottom">
|
||||
<div class="product_image col-3">
|
||||
<div class="image image img-thumbnail"></div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span class="quantity"></span>
|
||||
x
|
||||
<span class="product_name"></span>
|
||||
<div class="customProductData col-12 mt-1 small"></div>
|
||||
</div>
|
||||
<?php if ($show_price and $currencyDisplay->_priceConfig['salesPrice'][0]) : ?>
|
||||
<div class="col-3 text-end">
|
||||
<span class="subtotal_with_tax"></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<div class="vmcontainer vm_cart_products container small">
|
||||
<?php foreach ($data->products as $product) : ?>
|
||||
<div class="product_row row align-items-center pb-2 mb-2 border-bottom">
|
||||
<div class="product_image col-3">
|
||||
<?php if ( VmConfig::get('oncheckout_show_images')) : ?>
|
||||
<div class="image img-thumbnail"><?php echo $product['image']; ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<span class="quantity">
|
||||
<?php echo $product['quantity'] ?>
|
||||
</span>
|
||||
x
|
||||
<span class="product_name">
|
||||
<?php echo $product['product_name'] ?>
|
||||
</span>
|
||||
<div class="customProductData col-12 mt-1 small">
|
||||
<?php echo $product['customProductData'] ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($show_price and $currencyDisplay->_priceConfig['salesPrice'][0]) : ?>
|
||||
<div class="col-3 text-end text-nowrap">
|
||||
<span class="subtotal_with_tax">
|
||||
<?php echo $product['subtotal_with_tax'] ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="show_cart_m d-flex align-items-center container">
|
||||
<a class="btn btn-secondary btn-sm show-cart me-auto" href="<?php echo $data->cart_show_link; ?>" rel="nofollow">
|
||||
<?php echo vmText::_('COM_VIRTUEMART_CART_SHOW'); ?>
|
||||
</a>
|
||||
<span class="total small">
|
||||
<?php echo !empty($data->products) ? $data->billTotal : ''; ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($view != 'cart' and $view != 'user') : ?>
|
||||
<div class="payments-signin-button"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<noscript>
|
||||
<?php echo vmText::_('MOD_VIRTUEMART_CART_AJAX_CART_PLZ_JAVASCRIPT') ?>
|
||||
</noscript>
|
||||
</div>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
|
||||
$category_id = vRequest::getInt ('virtuemart_category_id', 0);
|
||||
$sublevel = $params->get('level', 0);
|
||||
?>
|
||||
<ul class="vm-menu list-unstyled<?php echo $class_sfx ? ' ' . $class_sfx : ''; ?>">
|
||||
<?php foreach ($categories as $category) : ?>
|
||||
<?php
|
||||
$active_menu = '';
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$category->virtuemart_category_id);
|
||||
$cattext = $category->category_name;
|
||||
|
||||
if (in_array( $category->virtuemart_category_id, $parentCategories)) {
|
||||
$active_menu = ' active';
|
||||
}
|
||||
?>
|
||||
<li class="border-bottom<?php echo $active_menu ?>">
|
||||
<?php echo HTMLHelper::link($caturl, $cattext); ?>
|
||||
<?php if (!empty($category->childs) && $sublevel > 0) : ?>
|
||||
<ul class="vm-submenu<?php echo $class_sfx; ?> list-unstyled small px-3 py-1 bg-light">
|
||||
<?php foreach ($category->childs as $child) : ?>
|
||||
<?php
|
||||
$active_menu = '';
|
||||
if ($child->virtuemart_category_id == $category_id) {
|
||||
$active_menu = ' active';
|
||||
}
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$child->virtuemart_category_id);
|
||||
$cattext = vmText::_($child->category_name);
|
||||
?>
|
||||
<li class="border-bottom<?php echo $active_menu ?>">
|
||||
<?php echo HTMLHelper::link($caturl, $cattext); ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
|
||||
\Joomla\CMS\HTML\HTMLHelper::_('bootstrap.collapse');
|
||||
|
||||
$doc = Factory::getDocument();
|
||||
$wa = $doc->getWebAssetManager();
|
||||
$wa->addInlineScript('jQuery(function($) {
|
||||
$(\'.vm-menu-btn\').click(function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
');
|
||||
|
||||
$category_id = vRequest::getInt ('virtuemart_category_id', 0);
|
||||
$sublevel = $params->get('level', 0);
|
||||
$btnIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/>
|
||||
</svg>';
|
||||
?>
|
||||
<ul class="vm-menu vm-menu-current list-unstyled<?php echo $class_sfx ? ' ' . $class_sfx : ''; ?>">
|
||||
<?php foreach ($categories as $category) : ?>
|
||||
<?php
|
||||
$active_menu = '';
|
||||
|
||||
if (in_array( $category->virtuemart_category_id, $parentCategories)) {
|
||||
$active_menu = ' active';
|
||||
}
|
||||
|
||||
$has_children = !empty($category->childs) ? ' has-children' : '';
|
||||
$collapsed = empty($active_menu) ? ' collapsed' : '';
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$category->virtuemart_category_id);
|
||||
$btn = '<button class="vm-menu-btn' . $collapsed . '" type="button" data-bs-toggle="collapse" href="#vm-menu-current-' . $category->virtuemart_category_id . '" role="button" aria-expanded="false" aria-controls="vm-menu-current-' . $category->virtuemart_category_id . '">' . $btnIcon . '</button>';
|
||||
$submenu_btn = !empty($category->childs) && $sublevel > 0 ? $btn : '';
|
||||
$cattext = $category->category_name . $submenu_btn;
|
||||
?>
|
||||
<li class="border-bottom<?php echo $active_menu . $has_children; ?>">
|
||||
<?php echo HTMLHelper::link($caturl, $cattext); ?>
|
||||
<?php if (!empty($category->childs) && $sublevel > 0) : ?>
|
||||
<div class="collapse<?php echo !empty($active_menu) ? ' show' : ''; ?>" id="vm-menu-current-<?php echo $category->virtuemart_category_id; ?>">
|
||||
<ul class="vm-submenu<?php echo $class_sfx; ?> list-unstyled small px-3 py-1 bg-light">
|
||||
<?php foreach ($category->childs as $child) : ?>
|
||||
<?php
|
||||
$active_menu = '';
|
||||
if ($child->virtuemart_category_id == $category_id) {
|
||||
$active_menu = ' active';
|
||||
}
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$child->virtuemart_category_id);
|
||||
$childcattext = $child->category_name;
|
||||
?>
|
||||
<li class="border-bottom<?php echo $active_menu ?>">
|
||||
<?php echo HTMLHelper::link($caturl, $childcattext); ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
|
||||
\Joomla\CMS\HTML\HTMLHelper::_('bootstrap.collapse');
|
||||
|
||||
$doc = Factory::getDocument();
|
||||
$wa = $doc->getWebAssetManager();
|
||||
$wa->addInlineScript('jQuery(function($) {
|
||||
$(\'.vm-menu-btn\').click(function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
');
|
||||
|
||||
$category_id = vRequest::getInt ('virtuemart_category_id', 0);
|
||||
$sublevel = $params->get('level', 0);
|
||||
$btnIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/>
|
||||
</svg>';
|
||||
?>
|
||||
<ul id="vm-menu-default-<?php echo $module->id; ?>" class="vm-menu vm-menu-default accordion list-unstyled<?php echo $class_sfx ? ' ' . $class_sfx : ''; ?>">
|
||||
<?php foreach ($categories as $category) : ?>
|
||||
<?php
|
||||
$active_menu = '';
|
||||
|
||||
if (in_array( $category->virtuemart_category_id, $parentCategories)) {
|
||||
$active_menu = ' active';
|
||||
}
|
||||
|
||||
$has_children = !empty($category->childs) ? ' has-children' : '';
|
||||
$collapsed = empty($active_menu) ? ' collapsed' : '';
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$category->virtuemart_category_id);
|
||||
$btn = '<button class="vm-menu-btn' . $collapsed . '" type="button" data-bs-toggle="collapse" href="#vm-menu-default-' . $category->virtuemart_category_id . '" role="button" aria-expanded="false" aria-controls="vm-menu-default-' . $category->virtuemart_category_id . '">' . $btnIcon . '</button>';
|
||||
$submenu_btn = !empty($category->childs) && $sublevel > 0 ? $btn : '';
|
||||
$cattext = $category->category_name . $submenu_btn;
|
||||
?>
|
||||
<li class="accordion-item border-bottom<?php echo $active_menu . $has_children; ?>">
|
||||
<?php echo HTMLHelper::link($caturl, $cattext); ?>
|
||||
<?php if (!empty($category->childs) && $sublevel > 0) : ?>
|
||||
<div class="accordion-collapse collapse<?php echo !empty($active_menu) ? ' show' : ''; ?>" id="vm-menu-default-<?php echo $category->virtuemart_category_id; ?>" data-bs-parent="#vm-menu-default-<?php echo $module->id; ?>">
|
||||
<ul class="vm-submenu<?php echo $class_sfx; ?> list-unstyled small px-3 py-1 bg-light">
|
||||
<?php foreach ($category->childs as $child) : ?>
|
||||
<?php
|
||||
$active_menu = '';
|
||||
if ($child->virtuemart_category_id == $category_id) {
|
||||
$active_menu = ' active';
|
||||
}
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$child->virtuemart_category_id);
|
||||
$childcattext = $child->category_name;
|
||||
?>
|
||||
<li class="border-bottom<?php echo $active_menu ?>">
|
||||
<?php echo HTMLHelper::link($caturl, $childcattext); ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
$categoryModel->addImages($categories);
|
||||
$categories_per_row = vmConfig::get('categories_per_row');
|
||||
$bscol = $module->position == 'sidebar-left' || $module->position == 'sidebar-right' ? '6' : '3';
|
||||
?>
|
||||
|
||||
<ul class="vm-categories-wall list-unstyled p-0 row <?php echo $class_sfx ?>">
|
||||
<?php foreach ($categories as $category) : ?>
|
||||
<?php
|
||||
$caturl = Route::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='.$category->virtuemart_category_id);
|
||||
$catname = $category->category_name ;
|
||||
?>
|
||||
<li class="vm-categories-wall-catwrapper col-6 col-md-4 col-xl-<?php echo $bscol; ?>">
|
||||
<div class="vm-categories-wall-spacer text-center">
|
||||
<a href="<?php echo $caturl; ?>">
|
||||
<?php echo $category->images[0]->displayMediaThumb('class="vm-categories-wall-img img-fluid mb-3"',false) ?>
|
||||
<div class="vm-subcategory-title fw-normal pt-2 mb-2 border-top lh-sm"><?php echo $catname; ?></div>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
vmJsApi::cssSite();
|
||||
|
||||
$selectedCurrency = $currencyModel->getCurrency($virtuemart_currency_id);
|
||||
?>
|
||||
|
||||
<?php if ($text_before) : ?>
|
||||
<p class="small"><?php echo $text_before; ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form class="virtuemart-currency-form d-none" action="<?php echo vmURI::getCurrentUrlBy('get',true) ?>" method="post">
|
||||
<input type="hidden" name="virtuemart_currency_id" value="" />
|
||||
</form>
|
||||
|
||||
<div class="vm-currencies-dropdown dropdown">
|
||||
<button class="btn btn-link btn-sm dropdown-toggle p-0" type="button" data-bs-toggle="dropdown" aria-expanded="false"><?php echo $selectedCurrency->currency_code_3 . ' ' . $selectedCurrency->currency_symbol; ?></button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<?php foreach ($currencies as $currency) : ?>
|
||||
<li><button class="dropdown-item" data-cur-id="<?php echo $currency->virtuemart_currency_id;?>"><?php echo $currency->currency_txt; ?></button></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$j = 'jQuery(document).ready(function($) {
|
||||
$(\'.dropdown-item\').click(function(e) {
|
||||
var currencyId = $(this).attr(\'data-cur-id\');
|
||||
$(\'input[name="virtuemart_currency_id"]\').val(currencyId);
|
||||
$(\'.virtuemart-currency-form\').submit();
|
||||
});
|
||||
})';
|
||||
|
||||
vmJsApi::addJScript('sendFormChange',$j);
|
||||
echo vmJsApi::writeJS();
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
$bscol = round(12 / $manufacturers_per_row);
|
||||
?>
|
||||
|
||||
<div class="vmgroup<?php echo $params->get( 'moduleclass_sfx' ) ?>">
|
||||
<?php if ($headerText) : ?>
|
||||
<div class="vm-header-text mb-4"><?php echo $headerText ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($display_style =="div") : ?>
|
||||
<div class="vm-manufacturer-module<?php echo $params->get('moduleclass_sfx'); ?> row gy-4 mb-4">
|
||||
<?php foreach ($manufacturers as $manufacturer) : ?>
|
||||
<?php $link = Route::_('index.php?option=com_virtuemart&view=manufacturer&virtuemart_manufacturer_id=' . $manufacturer->virtuemart_manufacturer_id); ?>
|
||||
<div class="col-6 col-md-4 col-lg-<?php echo $bscol; ?>">
|
||||
<a href="<?php echo $link; ?>">
|
||||
<?php
|
||||
if ($manufacturer->images && ($show == 'image' or $show == 'all' ))
|
||||
{
|
||||
echo $manufacturer->images[0]->displayMediaThumb('',false);
|
||||
}
|
||||
?>
|
||||
<?php if ($show == 'text' or $show == 'all') : ?>
|
||||
<div><?php echo $manufacturer->mf_name; ?></div>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<ul class="vmmanufacturer<?php echo $params->get('moduleclass_sfx'); ?> row mb-4">
|
||||
<?php foreach ($manufacturers as $manufacturer) : ?>
|
||||
<?php $link = Route::_('index.php?option=com_virtuemart&view=manufacturer&virtuemart_manufacturer_id=' . $manufacturer->virtuemart_manufacturer_id); ?>
|
||||
<li class="<?php echo ($show == 'image' or $show == 'all') ? 'col-6 mb-3 text-center' : 'col-12 pb-2 mb-2 border-bottom'; ?>">
|
||||
<a href="<?php echo $link; ?>">
|
||||
<?php if ($manufacturer->images && ($show == 'image' or $show == 'all' )) : ?>
|
||||
<?php echo $manufacturer->images[0]->displayMediaThumb('class="img-thumbnail"',false);?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($show == 'text' or $show == 'all' ) : ?>
|
||||
<?php
|
||||
if ($show == 'all') {
|
||||
$class = "text-center";
|
||||
}
|
||||
?>
|
||||
|
||||
<div>
|
||||
<?php echo $manufacturer->mf_name; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($footerText) : ?>
|
||||
<div class="vm-footer-text<?php echo $params->get( 'moduleclass_sfx' ) ?>">
|
||||
<?php echo $footerText ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,167 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined ('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
|
||||
// Load Bootstrap tooltip
|
||||
\Joomla\CMS\HTML\HTMLHelper::_('bootstrap.tooltip');
|
||||
|
||||
vmJsApi::jPrice();
|
||||
vmJsApi::cssSite();
|
||||
|
||||
$ratingModel = VmModel::getModel('ratings');
|
||||
$showRating = $ratingModel->showRating();
|
||||
|
||||
$emptyStar = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star" viewBox="0 0 16 16">
|
||||
<path d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.56.56 0 0 0-.163-.505L1.71 6.745l4.052-.576a.53.53 0 0 0 .393-.288L8 2.223l1.847 3.658a.53.53 0 0 0 .393.288l4.052.575-2.906 2.77a.56.56 0 0 0-.163.506l.694 3.957-3.686-1.894a.5.5 0 0 0-.461 0z"/>
|
||||
</svg>';
|
||||
|
||||
$star = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>';
|
||||
|
||||
$bscol = ' col-xl-' . floor (12 / $products_per_row);
|
||||
?>
|
||||
|
||||
<div class="vm-products-module<?php echo $params->get ('moduleclass_sfx') ?>">
|
||||
<?php if ($headerText) : ?>
|
||||
<div class="vm-header-text mb-4"><?php echo $headerText ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($display_style == "div") : ?>
|
||||
<div class="vm-product-grid<?php echo $params->get ('moduleclass_sfx'); ?> row gy-4 g-xl-5">
|
||||
<?php foreach ($products as $product) : ?>
|
||||
<div class="product-container d-flex flex-column col-6 col-md-6 col-lg-4<?php echo $bscol; ?> pb-4">
|
||||
<div class="vm-product-media-container text-center d-flex flex-column justify-content-center"<?php echo VmConfig::get('img_height', 0) ? ' style="min-height:' . VmConfig::get('img_height', 0) . 'px"' : ''?>>
|
||||
<?php
|
||||
$image = !empty($product->images[0]) ? $product->images[0]->displayMediaThumb ('class="vm-products-module-img img-fluid"', FALSE) : '';
|
||||
echo HTMLHelper::_ ('link', Route::_ ('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id=' . $product->virtuemart_product_id . '&virtuemart_category_id=' . $product->virtuemart_category_id), $image, array('title' => $product->product_name));
|
||||
?>
|
||||
</div>
|
||||
<div class="vm-product-rating-container d-flex justify-content-between pb-2 my-3 border-bottom">
|
||||
<?php if ($showRating) : ?>
|
||||
<?php
|
||||
$productRating = $ratingModel->getRatingByProduct($product->virtuemart_product_id, true);
|
||||
$maxrating = VmConfig::get('vm_maximum_rating_scale', 5);
|
||||
?>
|
||||
<?php if (empty($productRating->rating)) : ?>
|
||||
<div class="vm-ratingbox-unrated d-inline-block" title="<?php echo vmText::_('COM_VIRTUEMART_UNRATED'); ?>" data-bs-toggle="tooltip">
|
||||
<?php
|
||||
for ($i=0; $i<5; $i++)
|
||||
{
|
||||
echo $emptyStar;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php $ratingwidth = $productRating->rating * 16; ?>
|
||||
<div class="vm-ratingbox-container d-inline-block position-relative">
|
||||
<div class="vm-ratingbox-unrated d-inline-block">
|
||||
<?php
|
||||
for ($i=0; $i<5; $i++)
|
||||
{
|
||||
echo $emptyStar;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="vm-ratingbox-rated d-inline-block" title="<?php echo (vmText::_("COM_VIRTUEMART_RATING_TITLE") . ' ' . round($productRating->rating, 2) . '/' . $maxrating) ?>" data-bs-toggle="tooltip">
|
||||
<div class="vm-ratingbox-bar overflow-x-hidden text-nowrap" style="width:<?php echo $ratingwidth.'px'; ?>">
|
||||
<?php
|
||||
for ($i=0; $i<5; $i++)
|
||||
{
|
||||
echo $star;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php echo shopFunctionsF::renderVmSubLayout('displaystock', array('product'=>$product)); ?>
|
||||
</div>
|
||||
|
||||
<?php $url = Route::_ ('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id=' . $product->virtuemart_product_id . '&virtuemart_category_id=' .$product->virtuemart_category_id); ?>
|
||||
|
||||
<h3 class="vm-product-title text-center mb-2">
|
||||
<a href="<?php echo $url ?>">
|
||||
<?php echo $product->product_name; ?>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<p class="vm-product-s-desc text-center text-secondary">
|
||||
<?php echo shopFunctionsF::limitStringByWord ($product->product_s_desc, 60, ' ...') ?>
|
||||
</p>
|
||||
|
||||
<div class="product-price vm-simple-price-display text-center d-flex justify-content-center align-items-center mb-auto<?php echo $product->prices['discountAmount'] ? ' vm-has-discount' : ''?>">
|
||||
<?php
|
||||
if ($show_price) {
|
||||
if (!empty($product->prices['salesPrice'])) {
|
||||
echo $currency->createPriceDiv ('salesPrice', '', $product->prices, FALSE, FALSE, 1.0, TRUE);
|
||||
}
|
||||
|
||||
if ($product->prices['discountAmount']) {
|
||||
echo $currency->createPriceDiv ('basePriceWithTax', '', $product->prices, FALSE, FALSE, 1.0, TRUE);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php if ($show_addtocart) : ?>
|
||||
<?php echo shopFunctionsF::renderVmSubLayout('addtocart',array('product'=>$product)); ?>
|
||||
<?php else : ?>
|
||||
<a class="btn btn-secondary w-100 mt-3" href="<?php echo $url; ?>"><?php echo vmText::_ ( 'COM_VIRTUEMART_PRODUCT_DETAILS' ); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<ul class="vm-product-list p-0 <?php echo $params->get ('moduleclass_sfx'); ?> productdetails">
|
||||
<?php foreach ($products as $product) : ?>
|
||||
<li class="product-container list-unstyled p-0 d-flex flex-column col-12 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-5">
|
||||
<?php
|
||||
$image = !empty($product->images[0]) ? $product->images[0]->displayMediaThumb ('class="vm-products-module-img img-fluid"', FALSE) : '';
|
||||
echo HTMLHelper::_ ('link', Route::_ ('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id=' . $product->virtuemart_product_id . '&virtuemart_category_id=' . $product->virtuemart_category_id), $image, array('title' => $product->product_name));
|
||||
?>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<?php $url = Route::_ ('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id=' . $product->virtuemart_product_id . '&virtuemart_category_id=' .$product->virtuemart_category_id); ?>
|
||||
|
||||
<h3 class="vm-product-title mb-2">
|
||||
<a href="<?php echo $url ?>">
|
||||
<?php echo $product->product_name; ?>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<div class="product-price vm-simple-price-display d-flex justify-content-start align-items-center mb-2<?php echo $product->prices['discountAmount'] ? ' vm-has-discount' : ''?>">
|
||||
<?php
|
||||
if ($show_price) {
|
||||
if (!empty($product->prices['salesPrice'])) {
|
||||
echo $currency->createPriceDiv ('salesPrice', '', $product->prices, FALSE, FALSE, 1.0, TRUE);
|
||||
}
|
||||
|
||||
if ($product->prices['discountAmount']) {
|
||||
echo $currency->createPriceDiv ('basePriceWithTax', '', $product->prices, FALSE, FALSE, 1.0, TRUE);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-sm btn-secondary w-100" href="<?php echo $url; ?>"><?php echo vmText::_ ( 'COM_VIRTUEMART_PRODUCT_DETAILS' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($footerText) : ?>
|
||||
<div class="vm-footer-text<?php echo $params->get ('moduleclass_sfx') ?>">
|
||||
<?php echo $footerText ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('_JEXEC') or die('Restricted access');
|
||||
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
vmJsApi::cssSite();
|
||||
?>
|
||||
|
||||
<form action="<?php echo Route::_('index.php?option=com_virtuemart&view=category&search=true&limitstart=0&virtuemart_category_id='.$category_id ); ?>" method="get">
|
||||
<div class="<?php echo $button && $button_text == vmText::_ ('MOD_VIRTUEMART_SEARCH_GO') ? 'vmbasic-search ' : ''; ?>input-group mod-vm-search<?php echo $params->get('moduleclass_sfx') ? ' ' . $params->get('moduleclass_sfx') : ''; ?>">
|
||||
<?php
|
||||
$output = '<input name="keyword" id="mod_virtuemart_search" maxlength="'.$maxlength.'" placeholder="'.$text.'" class="form-control'. $moduleclass_sfx .'" type="text" size="'.$width.'" />';
|
||||
$image = Uri::base() . $imagepath;
|
||||
$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
|
||||
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
|
||||
</svg>';
|
||||
|
||||
if ($button) :
|
||||
if ($imagebutton && $imagepath) :
|
||||
$button = '<button type="submit" class="btn ' . $moduleclass_sfx . '"><img src="' . $image . '" alt="' . $button_text . '" /></button>';
|
||||
elseif ($button_text != vmText::_ ('MOD_VIRTUEMART_SEARCH_GO')) :
|
||||
$button = '<button type="submit" class="btn btn-primary ' . $moduleclass_sfx . '">' . $button_text . '</button>';
|
||||
else :
|
||||
$button = '<button type="submit" class="btn btn-svg '.$moduleclass_sfx.'">' . $svg . '</button>';
|
||||
endif;
|
||||
|
||||
switch ($button_pos) :
|
||||
case 'right' :
|
||||
$output = $output.$button;
|
||||
break;
|
||||
case 'left' :
|
||||
$output = $button.$output;
|
||||
break;
|
||||
default :
|
||||
$output = $output.$button;
|
||||
break;
|
||||
endswitch;
|
||||
endif;
|
||||
|
||||
echo $output;
|
||||
?>
|
||||
</div>
|
||||
<input type="hidden" name="limitstart" value="0" />
|
||||
<input type="hidden" name="option" value="com_virtuemart" />
|
||||
<input type="hidden" name="view" value="category" />
|
||||
<input type="hidden" name="virtuemart_category_id" value="<?php echo $category_id; ?>"/>
|
||||
<?php
|
||||
if (!empty($set_Itemid))
|
||||
{
|
||||
echo '<input type="hidden" name="Itemid" value="'.$set_Itemid.'" />';
|
||||
}
|
||||
?>
|
||||
</form>
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- Copyright (C) 2025 Moko Consulting <jmiller@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: Joomla.Templates.Site
|
||||
INGROUP: Moko-Cassiopeia
|
||||
FILE: index.html
|
||||
BRIEF: Security redirect page to block folder access and forward to site root.
|
||||
-->
|
||||
|
||||
<!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>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user