primo commit
This commit is contained in:
7
media/fef/css/dark.min.css
vendored
Normal file
7
media/fef/css/dark.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
media/fef/css/fef-joomla.min.css
vendored
Normal file
7
media/fef/css/fef-joomla.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
media/fef/css/fef-reset.min.css
vendored
Normal file
7
media/fef/css/fef-reset.min.css
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/.akeeba-renderer-fef div,.akeeba-renderer-fef span,.akeeba-renderer-fef applet,.akeeba-renderer-fef object,.akeeba-renderer-fef iframe,.akeeba-renderer-fef h1,.akeeba-renderer-fef h2,.akeeba-renderer-fef h3,.akeeba-renderer-fef h4,.akeeba-renderer-fef h5,.akeeba-renderer-fef h6,.akeeba-renderer-fef p,.akeeba-renderer-fef blockquote,.akeeba-renderer-fef pre,.akeeba-renderer-fef a,.akeeba-renderer-fef abbr,.akeeba-renderer-fef acronym,.akeeba-renderer-fef address,.akeeba-renderer-fef big,.akeeba-renderer-fef cite,.akeeba-renderer-fef code,.akeeba-renderer-fef del,.akeeba-renderer-fef dfn,.akeeba-renderer-fef em,.akeeba-renderer-fef img,.akeeba-renderer-fef ins,.akeeba-renderer-fef kbd,.akeeba-renderer-fef q,.akeeba-renderer-fef s,.akeeba-renderer-fef samp,.akeeba-renderer-fef small,.akeeba-renderer-fef strike,.akeeba-renderer-fef strong,.akeeba-renderer-fef sub,.akeeba-renderer-fef sup,.akeeba-renderer-fef tt,.akeeba-renderer-fef var,.akeeba-renderer-fef b,.akeeba-renderer-fef u,.akeeba-renderer-fef center,.akeeba-renderer-fef dl,.akeeba-renderer-fef dt,.akeeba-renderer-fef dd,.akeeba-renderer-fef fieldset,.akeeba-renderer-fef form,.akeeba-renderer-fef label,.akeeba-renderer-fef legend,.akeeba-renderer-fef table,.akeeba-renderer-fef caption,.akeeba-renderer-fef tbody,.akeeba-renderer-fef tfoot,.akeeba-renderer-fef thead,.akeeba-renderer-fef tr,.akeeba-renderer-fef th,.akeeba-renderer-fef td,.akeeba-renderer-fef article,.akeeba-renderer-fef aside,.akeeba-renderer-fef canvas,.akeeba-renderer-fef details,.akeeba-renderer-fef embed,.akeeba-renderer-fef figure,.akeeba-renderer-fef figcaption,.akeeba-renderer-fef footer,.akeeba-renderer-fef header,.akeeba-renderer-fef hgroup,.akeeba-renderer-fef menu,.akeeba-renderer-fef nav,.akeeba-renderer-fef output,.akeeba-renderer-fef ruby,.akeeba-renderer-fef section,.akeeba-renderer-fef summary,.akeeba-renderer-fef time,.akeeba-renderer-fef mark,.akeeba-renderer-fef audio,.akeeba-renderer-fef video,.akeeba-renderer-fef input[type=submit]{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;box-sizing:border-box;line-height:inherit}.akeeba-renderer-fef article,.akeeba-renderer-fef aside,.akeeba-renderer-fef details,.akeeba-renderer-fef figcaption,.akeeba-renderer-fef figure,.akeeba-renderer-fef footer,.akeeba-renderer-fef header,.akeeba-renderer-fef hgroup,.akeeba-renderer-fef menu,.akeeba-renderer-fef nav,.akeeba-renderer-fef section{display:block}.akeeba-renderer-fef blockquote,.akeeba-renderer-fef q{quotes:none}.akeeba-renderer-fef blockquote:before,.akeeba-renderer-fef blockquote:after,.akeeba-renderer-fef q:before,.akeeba-renderer-fef q:after{content:"";content:none}.akeeba-renderer-fef table{border-spacing:0}.akeeba-renderer-fef input[type=text],.akeeba-renderer-fef input[type=password],.akeeba-renderer-fef input[type=number],.akeeba-renderer-fef input[type=email],.akeeba-renderer-fef input[type=color],.akeeba-renderer-fef input[type=date],.akeeba-renderer-fef input[type=datetime-local],.akeeba-renderer-fef input[type=month],.akeeba-renderer-fef input[type=range],.akeeba-renderer-fef input[type=search],.akeeba-renderer-fef input[type=tel],.akeeba-renderer-fef input[type=time],.akeeba-renderer-fef input[type=url],.akeeba-renderer-fef input[type=week],.akeeba-renderer-fef select,.akeeba-renderer-fef input[type=file]{height:2.25em}.akeeba-renderer-fef select{background-color:#fff}/*# sourceMappingURL=fef-reset.min.css.map */
|
||||
9
media/fef/css/reset.min.css
vendored
Normal file
9
media/fef/css/reset.min.css
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
* Copyright (c) 2017-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
*
|
||||
* Created by Crystal Harris for Akeeba Ltd, https://www.akeeba.com
|
||||
*
|
||||
* Licensed under the GNU General Public License (GPL) version 3 or, at your option, any later version of the license
|
||||
* published by the Free Software Foundation, https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
*/.akeeba-renderer-fef div,.akeeba-renderer-fef span,.akeeba-renderer-fef applet,.akeeba-renderer-fef object,.akeeba-renderer-fef iframe,.akeeba-renderer-fef h1,.akeeba-renderer-fef h2,.akeeba-renderer-fef h3,.akeeba-renderer-fef h4,.akeeba-renderer-fef h5,.akeeba-renderer-fef h6,.akeeba-renderer-fef p,.akeeba-renderer-fef blockquote,.akeeba-renderer-fef pre,.akeeba-renderer-fef a,.akeeba-renderer-fef abbr,.akeeba-renderer-fef acronym,.akeeba-renderer-fef address,.akeeba-renderer-fef big,.akeeba-renderer-fef cite,.akeeba-renderer-fef code,.akeeba-renderer-fef del,.akeeba-renderer-fef dfn,.akeeba-renderer-fef em,.akeeba-renderer-fef img,.akeeba-renderer-fef ins,.akeeba-renderer-fef kbd,.akeeba-renderer-fef q,.akeeba-renderer-fef s,.akeeba-renderer-fef samp,.akeeba-renderer-fef small,.akeeba-renderer-fef strike,.akeeba-renderer-fef strong,.akeeba-renderer-fef sub,.akeeba-renderer-fef sup,.akeeba-renderer-fef tt,.akeeba-renderer-fef var,.akeeba-renderer-fef b,.akeeba-renderer-fef u,.akeeba-renderer-fef center,.akeeba-renderer-fef dl,.akeeba-renderer-fef dt,.akeeba-renderer-fef dd,.akeeba-renderer-fef fieldset,.akeeba-renderer-fef form,.akeeba-renderer-fef label,.akeeba-renderer-fef legend,.akeeba-renderer-fef table,.akeeba-renderer-fef caption,.akeeba-renderer-fef tbody,.akeeba-renderer-fef tfoot,.akeeba-renderer-fef thead,.akeeba-renderer-fef tr,.akeeba-renderer-fef th,.akeeba-renderer-fef td,.akeeba-renderer-fef article,.akeeba-renderer-fef aside,.akeeba-renderer-fef canvas,.akeeba-renderer-fef details,.akeeba-renderer-fef embed,.akeeba-renderer-fef figure,.akeeba-renderer-fef figcaption,.akeeba-renderer-fef footer,.akeeba-renderer-fef header,.akeeba-renderer-fef hgroup,.akeeba-renderer-fef menu,.akeeba-renderer-fef nav,.akeeba-renderer-fef output,.akeeba-renderer-fef ruby,.akeeba-renderer-fef section,.akeeba-renderer-fef summary,.akeeba-renderer-fef time,.akeeba-renderer-fef mark,.akeeba-renderer-fef audio,.akeeba-renderer-fef video,.akeeba-renderer-fef input[type=submit]{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;box-sizing:border-box;line-height:inherit}.akeeba-renderer-fef article,.akeeba-renderer-fef aside,.akeeba-renderer-fef details,.akeeba-renderer-fef figcaption,.akeeba-renderer-fef figure,.akeeba-renderer-fef footer,.akeeba-renderer-fef header,.akeeba-renderer-fef hgroup,.akeeba-renderer-fef menu,.akeeba-renderer-fef nav,.akeeba-renderer-fef section{display:block}.akeeba-renderer-fef blockquote,.akeeba-renderer-fef q{quotes:none}.akeeba-renderer-fef blockquote:before,.akeeba-renderer-fef blockquote:after,.akeeba-renderer-fef q:before,.akeeba-renderer-fef q:after{content:"";content:none}.akeeba-renderer-fef table{border-spacing:0}.akeeba-renderer-fef input[type=text],.akeeba-renderer-fef input[type=password],.akeeba-renderer-fef input[type=number],.akeeba-renderer-fef input[type=email],.akeeba-renderer-fef input[type=color],.akeeba-renderer-fef input[type=date],.akeeba-renderer-fef input[type=datetime-local],.akeeba-renderer-fef input[type=month],.akeeba-renderer-fef input[type=range],.akeeba-renderer-fef input[type=search],.akeeba-renderer-fef input[type=tel],.akeeba-renderer-fef input[type=time],.akeeba-renderer-fef input[type=url],.akeeba-renderer-fef input[type=week],.akeeba-renderer-fef select,.akeeba-renderer-fef input[type=file]{height:2.25em}.akeeba-renderer-fef select{background-color:#fff}/*# sourceMappingURL=reset.css.map */
|
||||
9
media/fef/css/style.min.css
vendored
Normal file
9
media/fef/css/style.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
542
media/fef/fef.php
Normal file
542
media/fef/fef.php
Normal file
@ -0,0 +1,542 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
// Protect from unauthorized access
|
||||
use Joomla\CMS\Document\PreloadManagerInterface;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Utilities\ArrayHelper;
|
||||
|
||||
defined('_JEXEC') || die();
|
||||
|
||||
if (@file_exists(__DIR__ . '/version.php') && @is_file(__DIR__ . '/version.php') && @is_readable(__DIR__ . '/version.php'))
|
||||
{
|
||||
@include_once(__DIR__ . '/version.php');
|
||||
}
|
||||
|
||||
if (!defined('AKEEBAFEF_VERSION'))
|
||||
{
|
||||
define('AKEEBAFEF_VERSION', 'dev');
|
||||
define('AKEEBAFEF_DATE', gmdate('Y-m-d'));
|
||||
}
|
||||
|
||||
class AkeebaFEFHelper
|
||||
{
|
||||
/**
|
||||
* Media versioning tag
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public static $tag = null;
|
||||
|
||||
/**
|
||||
* The Akeeba FEF Loader object
|
||||
*
|
||||
* @var AkeebaFEFLoader
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static $loader;
|
||||
|
||||
/**
|
||||
* Is this Joomla 4?
|
||||
*
|
||||
* @var bool|null
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static $isJoomla4 = null;
|
||||
|
||||
/**
|
||||
* Loads the Akeeba Frontend Framework, both CSS and JS
|
||||
*
|
||||
* @param bool $withReset Should I also load the CSS reset for the FEF container?
|
||||
* @param bool $dark Include Dark Mode CSS?
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public static function load(bool $withReset = true, bool $dark = false)
|
||||
{
|
||||
self::loadCSSFramework();
|
||||
self::loadJSFramework();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the Akeeba FEF CSS Framework
|
||||
*
|
||||
* @param bool $withReset Should I also load the CSS reset for the FEF container?
|
||||
* @param bool $dark Include Dark Mode CSS?
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public static function loadCSSFramework(bool $withReset = true, bool $dark = false)
|
||||
{
|
||||
self::getLoader()->loadCSSFramework($withReset, $dark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the Akeeba FEF JavaScript Framework
|
||||
*
|
||||
* @param bool $minimal Should I load the minimal framework (without optional features linked to FEF CSS?)
|
||||
*
|
||||
* @return void
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public static function loadJSFramework(bool $minimal = false)
|
||||
{
|
||||
self::getLoader()->loadJSFramework($minimal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy (FEF 1.1.x) alias to loadFEFScript.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @see self::loadFEFScript
|
||||
* @deprecated 3.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static function loadScript(string $name): void
|
||||
{
|
||||
self::loadFEFScript($name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an Akeeba FEF JavaScript file and its dependencies.
|
||||
*
|
||||
* @param string $name The basename of the file, e.g. "Tabs"
|
||||
* @param bool $defer Should I defer loading of the file?
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public static function loadFEFScript(string $name, bool $defer = true): void
|
||||
{
|
||||
self::getLoader()->loadFEFScript($name, $defer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this Joomla 4 or later?
|
||||
*
|
||||
* @return bool
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function isJoomla4(): bool
|
||||
{
|
||||
if (!is_bool(self::$isJoomla4))
|
||||
{
|
||||
self::$isJoomla4 = version_compare(JVERSION, '3.999.999', 'gt');
|
||||
}
|
||||
|
||||
return self::$isJoomla4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a JavaScript file using the Joomla! API.
|
||||
*
|
||||
* Special considerations:
|
||||
*
|
||||
* We always load the minified version of the file. Joomla! will automatically use the non-minified one if Debug
|
||||
* Site is enabled.
|
||||
*
|
||||
* You can have browser-specific files, e.g. foo_firefox.min.js, foo_firefox_57.min.js etc. These are loaded
|
||||
* automatically instead of the foo.js file as needed.
|
||||
*
|
||||
* This method goes through Joomla's script loader, thus allowing template media overrides. The media overrides are
|
||||
* supposed to be in the templates/YOUR_TEMPLATE/js/fef folder for FEF.
|
||||
*
|
||||
* @param string $name The Joomla!-coded path of the file, e.g. 'foo/bar.min.js' for the JavaScript file
|
||||
* media/foo/js/bar.min.js
|
||||
*
|
||||
* @param bool $defer Should I load the script defered?
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.3
|
||||
*/
|
||||
private static function loadJS(string $name, bool $defer = true): void
|
||||
{
|
||||
$options = [
|
||||
'version' => self::getMediaVersion(),
|
||||
'relative' => true,
|
||||
'detectDebug' => false,
|
||||
'framework' => false,
|
||||
'pathOnly' => false,
|
||||
'detectBrowser' => true,
|
||||
];
|
||||
HTMLHelper::_('script', 'fef/' . $name . '.min.js', $options, [
|
||||
'defer' => $defer,
|
||||
'async' => false,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Preload the static resource we are definitely asking the browser to use for better performance.
|
||||
*
|
||||
* Yes, this is also useful for deferred scripts! On Joomla 4 this goes through Preload Manager which does an
|
||||
* HTTP/2 Push for the script files. This is **far** faster than the browser making a number of HEAD requests
|
||||
* to see if the scripts are cached then an equal (or smaller) number of GET requests to fetch the scripts.
|
||||
*/
|
||||
$options['pathOnly'] = 'true';
|
||||
$path = HTMLHelper::_('script', 'fef/' . $name . '.min.js', $options);
|
||||
|
||||
if (empty($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self::preloadResource($path . '?' . self::getMediaVersion(), ['as' => 'script']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a CSS file using the Joomla! API.
|
||||
*
|
||||
* Special considerations:
|
||||
*
|
||||
* We always as Joomla to load the minified version of a file. Joomla! will automatically use the non-minified one
|
||||
* if Debug Site is enabled.
|
||||
*
|
||||
* You can have browser-specific files, e.g. foo_firefox.min.css, foo_firefox_57.min.css etc. These are loaded
|
||||
* automatically instead of the foo.css file as needed.
|
||||
*
|
||||
* This method goes through Joomla's script loader, thus allowing template media overrides. The media overrides are
|
||||
* supposed to be in the templates/YOUR_TEMPLATE/css/fef folder for FEF.
|
||||
*
|
||||
* We are instructing the browser to preload the CSS file we are inserting in the HTML. This can cause a small
|
||||
* performance increase. On Joomla 4 the increase is most noticeable because we go through the Preload Manager
|
||||
* which can leverage HTTP/2 Push.
|
||||
*
|
||||
* When loading the main CSS file (joomla-fef) we preload the WOFF font files which will be most likely used by the
|
||||
* browser consuming the CSS. This allows the browser to fetch the font files before fully parsing the stylesheet,
|
||||
* saving some time.
|
||||
*
|
||||
* @param string $name The Joomla!-coded path of the file, e.g. 'foo/bar.min.css' for the stylesheet file
|
||||
* media/foo/css/bar.min.css
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.3
|
||||
*/
|
||||
private static function loadCSS(string $name): void
|
||||
{
|
||||
/**
|
||||
* IMPORTANT! The $attribs (final parameter) MUST ALWAYS be non-empty. Otherwise Joomla! 3.x bugs out.
|
||||
*/
|
||||
$options = [
|
||||
'version' => self::getMediaVersion(),
|
||||
'relative' => true,
|
||||
'detectDebug' => false,
|
||||
'pathOnly' => false,
|
||||
'detectBrowser' => true,
|
||||
];
|
||||
HTMLHelper::_('stylesheet', 'fef/' . $name . '.min.css', $options, [
|
||||
'type' => 'text/css',
|
||||
]);
|
||||
|
||||
// Preload the static resource we are definitely asking the browser to use for better performance
|
||||
$options['pathOnly'] = 'true';
|
||||
$path = HTMLHelper::_('stylesheet', 'fef/' . $name . '.min.css', $options, [
|
||||
'type' => 'text/css',
|
||||
]);
|
||||
|
||||
if (empty($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self::preloadResource($path . '?' . self::getMediaVersion(), ['as' => 'style']);
|
||||
|
||||
// Special case: loading the fef-joomla stylesheet. Preload the font files as well
|
||||
if ($name == 'fef-joomla')
|
||||
{
|
||||
$fontPath = dirname(dirname($path)) . '/fonts/akeeba/Akeeba-Products.woff';
|
||||
self::preloadResource($fontPath, ['as' => 'font', 'crossorigin' => 'anonymous']);
|
||||
|
||||
$fontPath = dirname(dirname($path)) . '/fonts/Ionicon/ionicons.woff';
|
||||
self::preloadResource($fontPath, ['as' => 'font', 'crossorigin' => 'anonymous']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload a resource.
|
||||
*
|
||||
* On Joomla 3 this adds a LINK tag to the HTML document, instructing the browser to preload the resource.
|
||||
*
|
||||
* On Joomla 4 we are using the document object's Preload Manager to leverage HTTP/2 Push if available.
|
||||
*
|
||||
* @param string $url The absolute or relative URL of the resource to preload.
|
||||
* @param array $options Preload options. You need to specify 'as' as the bare minimum.
|
||||
*
|
||||
* @return void
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function preloadResource(string $url, array $options): void
|
||||
{
|
||||
if (!self::isJoomla4() || !self::preloadResourceJoomla4($url, $options))
|
||||
{
|
||||
self::preloadResourceJoomla3($url, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload a resource on Joomla 3.
|
||||
*
|
||||
* This adds a LINK tag to the HTML document, instructing the browser to preload the resource.
|
||||
*
|
||||
* @param string $url The absolute or relative URL of the resource to preload.
|
||||
* @param array $options Preload options. You need to specify 'as' as the bare minimum.
|
||||
*
|
||||
* @return bool True if successful; false if we can't get the document, or can't add a LINK tag e.g. this is not
|
||||
* an HTMLDocument
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function preloadResourceJoomla3(string $url, array $options): bool
|
||||
{
|
||||
// Try to get Joomla's document object
|
||||
$document = self::getDocument();
|
||||
|
||||
// Make sure the document object implements addCustomTag
|
||||
if (!is_object($document) || !method_exists($document, 'addCustomTag'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$options['rel'] = 'preload';
|
||||
$options['href'] = self::relativeToAbsoluteURL($url);
|
||||
$document->addCustomTag('<link ' . ArrayHelper::toString($options) . '>');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload a resource on Joomla 4.
|
||||
*
|
||||
* We are using the document object's Preload Manager to leverage HTTP/2 Push if available.
|
||||
*
|
||||
* @param string $url The absolute or relative URL of the resource to preload.
|
||||
* @param array $options Preload options. You need to specify 'as' as the bare minimum.
|
||||
*
|
||||
* @return bool True if successful; false if we can't get the document, or can't add a LINK tag e.g. this is not
|
||||
* an HTMLDocument
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function preloadResourceJoomla4(string $url, array $options): bool
|
||||
{
|
||||
// Make sure we're in a version of Joomla which has support for the Preload Manager
|
||||
if (!interface_exists('\\Joomla\CMS\Document\PreloadManagerInterface'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to get Joomla's document object
|
||||
$document = self::getDocument();
|
||||
|
||||
// Make sure the document object implements getPreloadManager
|
||||
if (!is_object($document) || !method_exists($document, 'getPreloadManager'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to get the preload manager
|
||||
try
|
||||
{
|
||||
$preloadManager = $document->getPreloadManager();
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the preload manager is an object implementing the PreloadManagerInterface
|
||||
if (!is_object($preloadManager) || !($preloadManager instanceof PreloadManagerInterface))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$absoluteUrl = self::relativeToAbsoluteURL($url);
|
||||
$preloadManager->preload($absoluteUrl, $options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Joomla document object
|
||||
*
|
||||
* @return JDocument|\Joomla\CMS\Document\Document|null NULL if we can't retrieve the document object.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function getDocument()
|
||||
{
|
||||
// Get the CMS application
|
||||
try
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make sure it's an object implementing getDocument
|
||||
if (!is_object($app) || !method_exists($app, 'getDocument'))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to get the document
|
||||
try
|
||||
{
|
||||
$document = $app->getDocument();
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a relative URL to an absolute URL for the current site
|
||||
*
|
||||
* @param string $url The possibly relative URL.
|
||||
*
|
||||
* @return string The definitely absolute URL.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function relativeToAbsoluteURL(string $url): string
|
||||
{
|
||||
static $baseUri;
|
||||
static $basePath;
|
||||
|
||||
// Get the base URI, e.g. 'https://localhost/test'
|
||||
if (empty($baseUri))
|
||||
{
|
||||
$baseUri = $baseUri ?? Uri::base();
|
||||
|
||||
if (substr($baseUri, -15) === '/administrator/')
|
||||
{
|
||||
$baseUri = substr($baseUri, 0, -15);
|
||||
}
|
||||
elseif (substr($baseUri, -14) === '/administrator')
|
||||
{
|
||||
$baseUri = substr($baseUri, 0, -14);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the base path, e.g. 'test'
|
||||
if (empty($basePath))
|
||||
{
|
||||
$basePath = $basePath ?? Uri::base(true);
|
||||
$basePath = empty($basePath) ? '' : trim($basePath, '/');
|
||||
|
||||
if ($basePath === 'administrator')
|
||||
{
|
||||
$basePath = '';
|
||||
}
|
||||
elseif (substr($basePath, -14) == '/administrator')
|
||||
{
|
||||
$basePath = trim(substr($basePath, 0, -14), '/');
|
||||
}
|
||||
}
|
||||
|
||||
if ((substr($url, 0, 2) == '//') ||
|
||||
(substr($url, 0, 7) == 'http://') ||
|
||||
(substr($url, 0, 8) == 'https://') ||
|
||||
(substr($url, 0, strlen($baseUri)) == $baseUri))
|
||||
{
|
||||
return $url;
|
||||
}
|
||||
|
||||
$url = ltrim($url, '/');
|
||||
|
||||
if ((strlen($basePath) != 0) && (substr($url, 0, strlen($basePath)) === $basePath))
|
||||
{
|
||||
$url = ltrim(substr($url, strlen($basePath)), '/');
|
||||
$url = ltrim($url, '/');
|
||||
}
|
||||
|
||||
return rtrim($baseUri, '/') . '/' . $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the media versioning tag. If it's not set, create one first.
|
||||
*
|
||||
* @return string
|
||||
* @since 1.1.0
|
||||
*/
|
||||
private static function getMediaVersion(): string
|
||||
{
|
||||
if (empty(self::$tag))
|
||||
{
|
||||
self::$tag = md5(AKEEBAFEF_VERSION . AKEEBAFEF_DATE . self::getApplicationSecret());
|
||||
}
|
||||
|
||||
return self::$tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the secret key for the Joomla! installation. Falls back to an MD5 of our file mod time.
|
||||
*
|
||||
* @return string
|
||||
* @since 1.1.0
|
||||
*/
|
||||
private static function getApplicationSecret(): string
|
||||
{
|
||||
$secret = md5(filemtime(__FILE__));
|
||||
|
||||
// Get the site's secret
|
||||
try
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
if (method_exists($app, 'get'))
|
||||
{
|
||||
return $app->get('secret', $secret);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or creates the Akeeba FEF Loader object.
|
||||
*
|
||||
* IMPORTANT: DO NOT SET A RETURN VALUE TYPE HINT. The AkeebaFEFLoader class is undefined until we load it in this
|
||||
* method. This causes a chicken and egg problem which results in a Fatal Error!
|
||||
*
|
||||
* @return AkeebaFEFLoader
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private static function getLoader()
|
||||
{
|
||||
if (!is_null(self::$loader))
|
||||
{
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
if (!class_exists('AkeebaFEFLoader'))
|
||||
{
|
||||
require_once __DIR__ . '/php/AkeebaFEFLoader.php';
|
||||
}
|
||||
|
||||
self::$loader = new AkeebaFEFLoader(function (string $name) {
|
||||
self::loadCSS($name);
|
||||
}, function (string $name, bool $defer) {
|
||||
self::loadJS($name, $defer);
|
||||
}, 'joomla');
|
||||
|
||||
return self::$loader;
|
||||
}
|
||||
}
|
||||
43
media/fef/file_fef.xml
Normal file
43
media/fef/file_fef.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--~
|
||||
~ Akeeba Frontend Framework (FEF)
|
||||
~
|
||||
~ @package fef
|
||||
~ @copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
~ @license GNU General Public License version 3, or later
|
||||
-->
|
||||
|
||||
<extension type="file" version="3.3" method="upgrade">
|
||||
<!-- Generic Metadata -->
|
||||
<name>file_fef</name>
|
||||
<author>Nicholas K. Dionysopoulos</author>
|
||||
<authorEmail>nicholas@dionysopoulos.me</authorEmail>
|
||||
<authorUrl>https://www.akeeba.com</authorUrl>
|
||||
<copyright>(C) 2017-2021 Akeeba Ltd.</copyright>
|
||||
<license>GNU GPL v3 or later</license>
|
||||
<version>2.1.0</version>
|
||||
<creationDate>2022-02-17</creationDate>
|
||||
<description>Akeeba Frontend Framework - The CSS framework for Akeeba Ltd extensions.</description>
|
||||
|
||||
<!-- Fileset definition -->
|
||||
<fileset>
|
||||
<files target="media/fef">
|
||||
<folder>css</folder>
|
||||
<folder>fonts</folder>
|
||||
<folder>images</folder>
|
||||
<folder>js</folder>
|
||||
<folder>php</folder>
|
||||
<filename>fef.php</filename>
|
||||
<filename>version.php</filename>
|
||||
<filename>version.txt</filename>
|
||||
</files>
|
||||
</fileset>
|
||||
|
||||
<!-- Installation / uninstallation script file -->
|
||||
<scriptfile>script.fef.php</scriptfile>
|
||||
|
||||
<!-- Update server -->
|
||||
<updateservers>
|
||||
<server type="extension" priority="1" name="Akeeba FEF">http://cdn.akeeba.com/updates/fef.xml</server>
|
||||
</updateservers>
|
||||
</extension>
|
||||
BIN
media/fef/fonts/Ionicon/ionicons.woff
Normal file
BIN
media/fef/fonts/Ionicon/ionicons.woff
Normal file
Binary file not shown.
BIN
media/fef/fonts/akeeba/Akeeba-Products.woff
Normal file
BIN
media/fef/fonts/akeeba/Akeeba-Products.woff
Normal file
Binary file not shown.
15
media/fef/js/Ajax.min.js
vendored
Normal file
15
media/fef/js/Ajax.min.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};window.akeeba.Ajax=window.akeebaAjax||{xhrSuccessStatus:{0:200,1223:204},requestArray:[],processingQueue:!1};
|
||||
akeeba.Ajax.ajax=function(b,a){"undefined"==typeof a&&(a=b,b=a.url);var c="undefined"==typeof a.type?"POST":a.type;c=c.toUpperCase();var e="undefined"==typeof a.data?{}:a.data,h=null,k="undefined"==typeof a.success?null:a.success,f="undefined"==typeof a.error?null:a.error;if("undefined"==typeof a.cache||!a.url){var l=(new Date).getTime()/1E3,m=parseInt(l,10);e._cacheBustingJunk=Math.round(1E3*(l-m))/1E3}"POST"==c||"PUT"==c?h=this.interpolateParameters(e):(b+=-1==b.indexOf("?")?"?":"&",b+=this.interpolateParameters(e));
|
||||
var d=new XMLHttpRequest;d.open(c,b);"POST"!=c&&"PUT"!=c||d.setRequestHeader("Content-Type","application/x-www-form-urlencoded");d.onload=function(g){g=akeeba.Ajax.xhrSuccessStatus[d.status]||d.status;var n=d.statusText,p="text"!==(d.responseType||"text")||"string"!==typeof d.responseText?d.response:d.responseText;d.getAllResponseHeaders();200===g?null!=k&&akeeba.Ajax.triggerCallbacks(k,p,n,d):f&&akeeba.Ajax.triggerCallbacks(f,d,"error",null)};d.onerror=function(g){f&&akeeba.Ajax.triggerCallbacks(f,
|
||||
d,"error",null)};window.attachEvent&&!window.addEventListener&&(d.onreadystatechange=function(){if(4===this.readyState){var g=akeeba.Ajax.xhrSuccessStatus[this.status]||this.status;if(200<=g&&400>g)d.onload();else d.onerror()}});d.ontimeout=function(){f&&akeeba.Ajax.triggerCallbacks(f,d,"timeout",null)};d.onabort=function(){f&&akeeba.Ajax.triggerCallbacks(f,d,"abort",null)};b="undefined"==typeof a.timeout?6E5:a.timeout;0<b&&(d.timeout=b);"undefined"!=typeof a.beforeSend&&!1===a.beforeSend(d,a)||d.send(h)};
|
||||
akeeba.Ajax.enqueue=function(b,a){"undefined"==typeof a&&(a=b,b=a.url);a.url=b;akeeba.Ajax.requestArray.push(a);akeeba.Ajax.processQueue()};akeeba.Ajax.interpolateParameters=function(b,a){a=a||"";var c="",e;for(e in b)b.hasOwnProperty(e)&&(0<c.length&&(c+="&"),c="object"!==typeof b[e]?""===a?c+(encodeURIComponent(e)+"="+encodeURIComponent(b[e])):c+(encodeURIComponent(a)+"["+encodeURIComponent(e)+"]="+encodeURIComponent(b[e])):c+akeeba.Ajax.interpolateParameters(b[e],e));return c};
|
||||
akeeba.Ajax.triggerCallbacks=function(){var b=Array.prototype.slice.call(arguments),a=b.shift();if("function"==typeof a)return a.apply(null,b);if(a instanceof Array)for(var c=0;c<a.length;c++)if(!1===a[c].apply(null,b))return!1;return null};akeeba.Ajax.processQueueHelper=function(){akeeba.Ajax.processingQueue=!1;setTimeout(akeeba.Ajax.processQueue,50)};
|
||||
akeeba.Ajax.processQueue=function(){if(!akeeba.Ajax.requestArray.length)akeeba.Ajax.processingQueue=!1;else if(!akeeba.Ajax.processingQueue){var b=akeeba.Ajax.requestArray.shift(),a=b.url,c="undefined"==typeof b.success?[]:b.success,e="undefined"==typeof b.error?[]:b.error;"object"==typeof c&&c instanceof Array||(c=[c]);"object"==typeof e&&e instanceof Array||(e=[e]);c.unshift(akeeba.Ajax.processQueueHelper);e.unshift(akeeba.Ajax.processQueueHelper);b.success=c;b.error=e;akeeba.Ajax.processingQueue=
|
||||
!0;akeeba.Ajax.ajax(a,b)}}; //# sourceMappingURL=Ajax.map
|
||||
35
media/fef/js/Modal.min.js
vendored
Normal file
35
media/fef/js/Modal.min.js
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
jsModal - A pure JavaScript modal dialog engine v1.0d
|
||||
http://jsmodal.com/
|
||||
|
||||
Author: Henry Rune Tang Kai <henry@henrys.se>
|
||||
|
||||
(c) Copyright 2013 Henry Tang Kai.
|
||||
|
||||
License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
Date: 2013-7-11
|
||||
|
||||
Modified by Akeeba Ltd:
|
||||
- [Oct 2016] Prefix "akeeba-modal-" instead of generic "modal-" to avoid conflicts with 3PD software e.g. Bootstrap.
|
||||
- [Oct 2016] Remove support for AJAX content. We use our own AJAX handlers which work around 3PD plugins corrupting content.
|
||||
? [Oct 2016] Added method show() which just calls open() for backwards compatibility reasons.
|
||||
? [Oct 2016] Added parameter "inherit" where you can give a query selector for an element whose content will be inherited by the modal.
|
||||
? [Oct 2016] open() returns the Modal object so that we can interact with it through external code.
|
||||
? [Nov 2016] Added parameter "iframe" where you can give a URL to load inside an IFRAME.
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};
|
||||
"undefined"==typeof akeeba.Modal&&(akeeba.Modal=function(){var e={},b={},f=document.createElement("div"),d=document.createElement("div"),k=document.createElement("div"),h=document.createElement("div"),m=document.createElement("div"),n=null,l,v;e.show=function(a){try{console.log("Using akeeba.Modal.show() is deprecated. Use .open() instead.")}catch(c){}return e.open(a)};e.open=function(a){b.width=a.width||"auto";b.height=a.height||"auto";b.lock=a.lock||!1;b.hideClose=a.hideClose||!1;b.draggable=a.draggable||
|
||||
!1;b.closeAfter=a.closeAfter||0;b.closeCallback=a.closeCallback||!1;b.openCallback=a.openCallback||!1;b.hideOverlay=a.hideOverlay||!1;l=function(){e.center({})};h.innerHTML="";var c=null;if(a.content)h.innerHTML=a.content;else if(a.inherit){if(c=a.inherit,"string"==typeof a.inherit&&(c=window.document.querySelector(a.inherit)),null!=c&&c.innerHTML)for(n=c;0<n.childNodes.length;)h.appendChild(n.childNodes[0])}else a.iframe&&(c=window.document.createElement("iframe"),c.setAttribute("src",a.iframe),
|
||||
c.setAttribute("width",a.width),c.setAttribute("height",a.height),c.setAttribute("frameborder",0),c.setAttribute("marginheight",0),c.setAttribute("marginwidth",0),h.appendChild(c));d.style.width=b.width;d.style.height=b.height;e.center({});if(b.lock||b.hideClose)m.style.visibility="hidden";b.hideOverlay||(f.style.visibility="visible");d.style.visibility="visible";document.onkeypress=function(g){27===g.keyCode&&!0!==b.lock&&e.close()};m.onclick=function(){if(b.hideClose)return!1;e.close()};f.onclick=
|
||||
function(){if(b.lock)return!1;e.close()};window.addEventListener?(window.addEventListener("resize",l,!1),window.addEventListener("load",l,!1)):window.attachEvent&&(window.attachEvent("onresize",l),window.attachEvent("onload",l));b.draggable?(k.style.cursor="move",k.onmousedown=function(g){e.drag(g);return!1}):k.onmousedown=function(){return!1};0<b.closeAfter&&(v=window.setTimeout(function(){e.close()},1E3*b.closeAfter));b.openCallback&&b.openCallback();return this};e.drag=function(a){var c=void 0!==
|
||||
window.event?window.event.clientX:a.clientX,g=void 0!==window.event?window.event.clientY:a.clientY,r=c-d.offsetLeft,p=g-d.offsetTop;document.onmousemove=function(q){c=void 0!==window.event?window.event.clientX:q.clientX;g=void 0!==window.event?window.event.clientY:q.clientY;d.style.left=0<c-r?c-r+"px":0;d.style.top=0<g-p?g-p+"px":0;document.onmouseup=function(){window.document.onmousemove=null}}};e.close=function(){if(!function(a){var c;if(""===a||0===a||"0"===a||null===a||!1===a||"undefined"===typeof a)return!0;
|
||||
if("object"==typeof a){for(c in a)return!1;return!0}return!1}(n)){for(;0<h.childNodes.length;)n.appendChild(h.childNodes[0]);n=null}h.innerHTML="";f.setAttribute("style","");f.style.cssText="";f.style.visibility="hidden";d.setAttribute("style","");d.style.cssText="";d.style.visibility="hidden";k.style.cursor="default";m.setAttribute("style","");m.style.cssText="";v&&window.clearTimeout(v);b.closeCallback&&b.closeCallback();window.removeEventListener?window.removeEventListener("resize",l,!1):window.detachEvent&&
|
||||
window.detachEvent("onresize",l)};e.center=function(a){var c=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight),g=Math.max(d.clientWidth,d.offsetWidth),r=Math.max(d.clientHeight,d.offsetHeight),p=0,q=0,t=0,u=0;"number"===typeof window.innerWidth?(p=window.innerWidth,q=window.innerHeight):document.documentElement&&document.documentElement.clientWidth&&(p=document.documentElement.clientWidth,q=document.documentElement.clientHeight);"number"===typeof window.pageYOffset?(u=window.pageYOffset,
|
||||
t=window.pageXOffset):document.body&&document.body.scrollLeft?(u=document.body.scrollTop,t=document.body.scrollLeft):document.documentElement&&document.documentElement.scrollLeft&&(u=document.documentElement.scrollTop,t=document.documentElement.scrollLeft);a.horizontalOnly||(d.style.top=u+q/2-r/2+"px");d.style.left=t+p/2-g/2+"px";f.style.height=c+"px";f.style.width="100%"};f.setAttribute("id","akeeba-modal-overlay");d.setAttribute("id","akeeba-modal-container");k.setAttribute("id","akeeba-modal-header");
|
||||
h.setAttribute("id","akeeba-modal-content");m.setAttribute("id","akeeba-modal-close");k.appendChild(m);d.appendChild(k);d.appendChild(h);f.style.visibility="hidden";d.style.visibility="hidden";window.addEventListener?window.addEventListener("load",function(){document.body.appendChild(f);document.body.appendChild(d)},!1):window.attachEvent&&window.attachEvent("onload",function(){document.body.appendChild(f);document.body.appendChild(d)});return e}()); //# sourceMappingURL=Modal.map
|
||||
48
media/fef/js/System.min.js
vendored
Normal file
48
media/fef/js/System.min.js
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
Math.uuid.js (v1.4)
|
||||
http://www.broofa.com
|
||||
mailto:robert@broofa.com
|
||||
|
||||
Copyright (c) 2009 Robert Kieffer
|
||||
Dual licensed under the MIT and GPL licenses.
|
||||
|
||||
Usage: Math.uuid()
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};"undefined"===typeof akeeba.System&&(akeeba.System={},akeeba.System.documentReady=function(a,b){},akeeba.System.notification={hasDesktopNotification:!1,iconURL:""},akeeba.System.params={AjaxURL:"",errorCallback:akeeba.System.modalErrorHandler,password:"",errorDialogId:"errorDialog",errorDialogMessageId:"errorDialogPre"},akeeba.System.modalDialog=null,akeeba.System.optionsStorage=null);
|
||||
"undefined"===typeof Math.uuid&&(Math.uuid=function(){var a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");return function(b,c){var d=[];c=c||a.length;if(b)for(var e=0;e<b;e++)d[e]=a[0|Math.random()*c];else for(d[8]=d[13]=d[18]=d[23]="-",d[14]="4",e=0;36>e;e++)d[e]||(b=0|16*Math.random(),d[e]=a[19===e?b&3|8:b]);return d.join("")}}());akeeba.System.forEach=function(a,b,c){for(var d=0;d<a.length;d++)b.call(c,d,a[d])};
|
||||
akeeba.System.array_merge=function(){var a=Array.prototype.slice.call(arguments),b={},c,d;var e=!0;for(d=0;d<a.length;d++)if(!(a[d]instanceof Array)){e=!1;break}if(e){e=[];for(d=0;d<a.length;d++)e=e.concat(a[d]);return e}var f;for(f=d=0;d<a.length;d++)if(a[d]instanceof Array)for(e=0;e<a[d].length;e++)b[f++]=a[d][e];else for(c in a[d])a[d].hasOwnProperty(c)&&(parseInt(c,10)+""===c?b[f++]=a[d][c]:b[c]=a[d][c]);return b};
|
||||
akeeba.System.array_diff=function(a){var b={},c=arguments.length,d="",e,f="";a:for(d in a)for(e=1;e<c;e++){var l=arguments[e];for(f in l)if(l[f]===a[d])continue a;b[d]=a[d]}return b};akeeba.System.findElement=function(a){if("undefined"===typeof a||null===a)return null;"string"===typeof a&&(a=document.getElementById(a));return"object"===typeof a&&a instanceof Element?a:null};
|
||||
akeeba.System.getOptions=function(a,b){"undefined"==typeof b&&(b=null);akeeba.System.optionsStorage||(akeeba.System.loadJoomlaOptions(),akeeba.System.loadOptions());return void 0!==akeeba.System.optionsStorage[a]?akeeba.System.optionsStorage[a]:"undefined"!==typeof Joomla&&"undefined"!==typeof Joomla.getOptions?Joomla.getOptions(a,b):b};
|
||||
akeeba.System.loadJoomlaOptions=function(){var a=document.querySelectorAll(".joomla-script-options");akeeba.System.iterateNodes(a,function(b){if(!akeeba.System.hasClass(b,"akeebaImported")){var c;str=b.text||b.textContent;(c=JSON.parse(str))&&akeeba.System.loadOptions(c);akeeba.System.addClass(b,"akeebaImported")}})};
|
||||
akeeba.System.loadOptions=function(a){if(!a){for(var b=document.querySelectorAll(".akeeba-script-options.new"),c,d,e=0,f=0,l=b.length;f<l;f++){d=b[f];c=d.text||d.textContent;if(c=JSON.parse(c))akeeba.System.loadOptions(c),e++;akeeba.System.removeClass(d,"new");akeeba.System.addClass(d,"loaded")}if(e)return}if(!akeeba.System.optionsStorage)akeeba.System.optionsStorage=a||{};else if(a)for(var g in a)a.hasOwnProperty(g)&&(akeeba.System.optionsStorage[g]=a[g])};
|
||||
akeeba.System.defaultErrorHandler=function(a){null!=a&&"undefined"!=typeof a&&alert("An error has occurred\n"+a)};
|
||||
akeeba.System.modalErrorHandler=function(a){var b=akeeba.System.getOptions("akeeba.System.params.errorDialogId",akeeba.System.params.errorDialogId),c=akeeba.System.getOptions("akeeba.System.params.errorDialogMessageId",akeeba.System.params.errorDialogMessageId);b=document.getElementById(b);var d="error";null!=b&&(document.getElementById(c).innerHTML=a,d=b.innerHTML);akeeba.Modal.open({content:d,width:"80%"})};
|
||||
akeeba.System.doAjax=function(a,b,c,d,e){null==d&&(d=!0);var f=(new Date).getTime()/1E3,l=parseInt(String(f),10);a._cacheBustingJunk=Math.round(1E3*(f-l))/1E3;null==e&&(e=6E5);f=akeeba.System.getOptions("akeeba.System.params.AjaxURL",akeeba.System.params.AjaxURL);a.hasOwnProperty("ajaxURL")&&(f=a.ajaxURL,delete a.url);var g=!0;a.hasOwnProperty("useTripleHash")&&(g=a.useTripleHash,delete a.useTripleHash);a.hasOwnProperty("parseResponseAsJSON")&&delete a.parseResponseAsJSON;null==c&&(c=akeeba.System.getOptions("akeeba.System.params.errorCallback",
|
||||
akeeba.System.params.errorCallback));null==c&&(c=akeeba.System.defaultErrorHandler);var p={type:"POST",url:f,cache:!1,data:a,timeout:e,success:function(h){if(g){var m=h.indexOf("###");if(-1===m){h=akeeba.System.sanitizeErrorMessage(h);c("Invalid AJAX data: "+h);return}}var k=h;g&&(0!==m&&(k=h.substr(m)),k=k.substr(3),m=k.lastIndexOf("###"),k=k.substr(0,m));try{var n=JSON.parse(k)}catch(q){k=akeeba.System.sanitizeErrorMessage(k);h=q.message+"\n<br/>\n<pre>\n"+k+"\n</pre>";c(h);return}b(n)},error:function(h,
|
||||
m,k){k=h.responseText?h.responseText:"";var n="<strong>AJAX Loading Error</strong><br/>HTTP Status: "+h.status+" ("+h.statusText+")<br/>";n=n+"Internal status: "+m+"<br/>XHR ReadyState: "+h.readyState+"<br/>";n=n+"Raw server response:<br/>"+akeeba.System.sanitizeErrorMessage(k);c(n)}};d?akeeba.Loader.add("akeeba.Ajax",function(){akeeba.Ajax.enqueue(p)}):akeeba.Loader.add("akeeba.Ajax",function(){akeeba.Ajax.ajax(p)})};
|
||||
akeeba.System.sanitizeErrorMessage=function(a){-1<a.indexOf("<script")&&(a="(HTML containing script tags)");return a};akeeba.System.notification.askPermission=function(){akeeba.System.getOptions("akeeba.System.notification.hasDesktopNotification",akeeba.System.notification.hasDesktopNotification)&&void 0!==window.Notification&&"default"===window.Notification.permission&&window.Notification.requestPermission()};
|
||||
akeeba.System.notification.notify=function(a,b,c){void 0!==window.Notification&&"granted"===window.Notification.permission&&(void 0===c&&(c=5E3),void 0===b&&(b=""),a=new window.Notification(a,{body:b,icon:akeeba.System.getOptions("akeeba.System.notification.iconURL",akeeba.System.notification.iconURL)}),0<c&&setTimeout(function(d){return function(){d.close()}}(a),c))};
|
||||
akeeba.System.data=function(){var a=0,b={};return{set:function(c,d,e){if(c.dataset)c.dataset[d]=e,null==e&&delete c.dataset[d];else{if(void 0===c.myCustomDataTag){var f=a++;c.myCustomDataTag=f}"undefined"==typeof b[f]&&(b[f]={});b[f][d]=e;var l="data-"+d.split(/(?=[A-Z])/).join("-").toLowerCase();c.setAttribute&&c.setAttribute(l,e);if(null==e)try{delete b[f][d],c.removeAttribute(l)}catch(g){b[f][d]=null}}},get:function(c,d,e){if(c.dataset)return"undefined"==typeof c.dataset[d]&&(c.dataset[d]=e),c.dataset[d];
|
||||
"undefined"==typeof e&&(e=null);"undefined"==typeof b[c.myCustomDataTag]&&(b[c.myCustomDataTag]={});var f="data-"+d.split(/(?=[A-Z])/).join("-").toLowerCase();"undefined"!==typeof c[f]&&(b[c.myCustomDataTag][d]=c[f]);"undefined"==typeof b[c.myCustomDataTag][d]&&this.set(c,d,e);return b[c.myCustomDataTag][d]}}}();
|
||||
akeeba.System.addEventListener=function(a,b,c){function d(e){var f=c.apply(this,arguments);!1===f&&(e.stopPropagation()&&e.stopPropagation(),e.preventDefault?e.preventDefault():e.returnValue=!1);return f}(a=akeeba.System.findElement(a))&&(a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,function(){var e=c.call(a,window.event);!1===e&&(window.event.returnValue=!1,window.event.cancelBubble=!0);return e}))};
|
||||
akeeba.System.removeEventListener=function(a,b,c){(a=akeeba.System.findElement(a))&&(a.removeEventListener?a.removeEventListener(b,c):a.detachEvent("on"+b,c))};akeeba.System.triggerEvent=function(a,b){if(a=akeeba.System.findElement(a))if("click"===b&&"function"===typeof a.click)a.click();else if(document.fireEvent&&"undefined"==typeof window.Event)a.fireEvent("on"+b);else{var c=document.createEvent("Event");c.initEvent(b,!0,!0);a.dispatchEvent(c)}};
|
||||
(function(a,b){function c(){if(!f){f=!0;for(var g=0;g<e.length;g++)e[g].fn.call(window,e[g].ctx);e=[]}}function d(){"complete"===document.readyState&&c()}b=b||akeeba.System;var e=[],f=!1,l=!1;b[a||"documentReady"]=function(g,p){f?setTimeout(function(){g(p)},1):(e.push({fn:g,ctx:p}),"complete"===document.readyState||!document.attachEvent&&"interactive"===document.readyState?setTimeout(c,1):l||(l=!0,document.addEventListener?(document.addEventListener("DOMContentLoaded",c,!1),window.addEventListener("load",
|
||||
c,!1)):(document.attachEvent("onreadystatechange",d),window.attachEvent("onload",c))))}})("documentReady",akeeba.System);akeeba.System.addClass=function(a,b){if(a){try{var c=a.className.split(" ")}catch(d){return}"string"==typeof b&&(b=b.split(" "));c=akeeba.System.array_merge(c,b);a.className="";for(property in c)c.hasOwnProperty(property)&&(a.className+=c[property]+" ");a.className.trim&&(a.className=a.className.trim())}};
|
||||
akeeba.System.removeClass=function(a,b){if(a){try{var c=a.className.split(" ")}catch(d){return}"string"==typeof b&&(b=b.split(" "));c=akeeba.System.array_diff(c,b);a.className="";for(property in c)c.hasOwnProperty(property)&&(a.className+=c[property]+" ");a.className.trim&&(a.className=a.className.trim())}};akeeba.System.hasClass=function(a,b){if(!a)return!1;try{var c=a.className.split(" ")}catch(d){return!1}for(i=0;i<c.length;i++)if(c[i]===b)return!0;return!1};
|
||||
akeeba.System.toggleClass=function(a,b){akeeba.System.hasClass(a,b)?akeeba.System.removeClass(a,b):akeeba.System.addClass(a,b)};akeeba.System.tableOrdering=function(a,b,c,d){"undefined"===typeof d&&(d=document.getElementById("adminForm"));d.filter_order.value=a;d.filter_order_Dir.value=b;akeeba.System.submitForm(c,d)};
|
||||
akeeba.System.submitForm=function(a,b,c){b||(b=document.getElementById("adminForm"));a&&(b.task.value=a);b.noValidate=!c;c?b.hasAttribute("novalidate")&&b.removeAttribute("novalidate"):b.setAttribute("novalidate","");a=document.createElement("input");a.style.display="none";a.type="submit";b.appendChild(a);a.click();b.removeChild(a)};
|
||||
akeeba.System.orderTable=function(){var a=document.getElementById("sortTable"),b=document.getElementById("directionTable");a=a.options[a.selectedIndex].value;var c="asc";a===akeeba.System.getOptions("akeeba.System.tableOrder","asc")&&(c=b.options[b.selectedIndex].value);akeeba.System.tableOrdering(a,c)};
|
||||
akeeba.System.iterateNodes=function(a,b,c){if("function"==typeof b&&("string"===typeof a&&(a=document.querySelectorAll(a)),0!==a.length)){var d;for(d=0;d<a.length;d++){var e=a[d];"undefined"!==typeof c?b(e,c):b(e)}}};
|
||||
akeeba.System.assignDefaultErrorHandler=function(){akeeba.System.params.errorCallback=akeeba.System.modalErrorHandler;if("undefined"===typeof akeeba.Modal)akeeba.System.params.errorCallback=akeeba.System.defaultErrorHandler;else{var a=akeeba.System.getOptions("akeeba.System.params.errorDialogId",akeeba.System.params.errorDialogId),b=akeeba.System.getOptions("akeeba.System.params.errorDialogMessageId",akeeba.System.params.errorDialogMessageId);if(""===a||null===a||""===b||null===b)akeeba.System.params.errorCallback=
|
||||
akeeba.System.defaultErrorHandler;else if(a=document.getElementById(a),b=document.getElementById(b),null===a||null===b)akeeba.System.params.errorCallback=akeeba.System.defaultErrorHandler}};
|
||||
akeeba.System.documentReady(function(){akeeba.System.assignDefaultErrorHandler();akeeba.System.iterateNodes(".akeebaGridViewCheckAll",function(a){akeeba.System.addEventListener(a,"click",function(){Joomla.checkAll(this)})});akeeba.System.iterateNodes(".akeebaGridViewOrderTable",function(a){akeeba.System.addEventListener(a,"change",akeeba.System.orderTable)});akeeba.System.iterateNodes(".akeebaGridViewAutoSubmitOnChange",function(a){akeeba.System.addEventListener(a,"change",function(){akeeba.System.submitForm()})})});
|
||||
akeeba.System.Text={strings:{},_:function(a,b){["akeeba.text","joomla.jtext"].forEach(function(c){var d=akeeba.System.getOptions(c);d&&(akeeba.System.Text.load(d),d={},d[c]=null,akeeba.System.loadOptions(d))});b=void 0===b?"":b;a=a.toUpperCase();return void 0!==akeeba.System.Text.strings[a]?akeeba.System.Text.strings[a]:"undefined"!=typeof Joomla.JText?Joomla.JText._(a,b):"undefined"!=typeof Joomla.Text?Joomla.Text._(a,b):b},load:function(a){for(var b in a)a.hasOwnProperty(b)&&(this.strings[b.toUpperCase()]=
|
||||
a[b]);return this}};
|
||||
akeeba.System.CommonEvents={onEventSubmit:function(a){var b=akeeba.System.data.get(a.currentTarget,"akeebasubmittarget",""),c=document.forms.adminForm?document.forms.adminForm:null;""!==b&&(c=document.getElementById(b));if(!c)return!0;c.submit();a.preventDefault();return!1},onClickConfirm:function(a){var b=akeeba.System.data.get(a.currentTarget,"akeebaconfirmmessage","");if(""===b||confirm(Joomla.Text._(b)))return!0;a.preventDefault();return!1},onEventOrderTable:function(a){a.preventDefault();Joomla.orderTable();
|
||||
return!1},init:function(){akeeba.System.iterateNodes(".akeebaCommonEventsOnChangeSubmit",function(a){akeeba.System.addEventListener(a,"change",akeeba.System.CommonEvents.onEventSubmit)});akeeba.System.iterateNodes(".akeebaCommonEventsOnClickSubmit",function(a){akeeba.System.addEventListener(a,"click",akeeba.System.CommonEvents.onEventSubmit)});akeeba.System.iterateNodes(".akeebaCommonEventsOnClickConfirm",function(a){akeeba.System.addEventListener(a,"click",akeeba.System.CommonEvents.onClickConfirm)});
|
||||
akeeba.System.iterateNodes(".akeebaCommonEventsOnChangeOrderTable",function(a){akeeba.System.addEventListener(a,"change",akeeba.System.CommonEvents.onEventOrderTable)})}};akeeba.System.CommonEvents.init(); //# sourceMappingURL=System.map
|
||||
15
media/fef/js/Tooltip.min.js
vendored
Normal file
15
media/fef/js/Tooltip.min.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
if("undefined"==typeof akeeba)var akeeba={};"undefined"==typeof akeeba.Tooltip&&(akeeba.Tooltip={});akeeba.Tooltip.enableFor=function(a,b){if("undefined"==typeof b||null===b)b=!0;if("object"==typeof a&&NodeList.prototype.isPrototypeOf(a))for(i=0;i<a.length;i++)akeeba.Tooltip.enableFor(a[i],b);else akeeba.System.addEventListener(a,"mouseenter",akeeba.Tooltip.onMouseEnter),akeeba.System.addEventListener(a,"mouseleave",akeeba.Tooltip.onMouseLeave),b&&akeeba.System.addEventListener(a,"click",akeeba.Tooltip.onClick)};
|
||||
akeeba.Tooltip.simpleTooltip=function(a){if(a.hasAttribute("title")){var b=a.getAttribute("title"),c="right";a.hasAttribute("data-akeeba-tooltip-position")&&(c=a.getAttribute("data-akeeba-tooltip-position"));akeeba.System.addClass(a,"akeeba-hasTooltip");var d=document.createElement("div");d.className="akeeba-tooltip-text akeeba-tooltip-text-"+c;d.innerHTML=b;a.appendChild(d);a.removeAttribute("title")}};
|
||||
akeeba.Tooltip.onMouseEnter=function(a){if(a.target.hasAttribute("data-content")){if(a.target.hasAttribute("data-tooltip-uuid"))var b=a.target.getAttribute("data-tooltip-uuid");else b=Math.uuid(),a.target.setAttribute("data-tooltip-uuid",b);if(null==document.getElementById("akeeba-tooltip-"+b)){var c=a.target.getAttribute("data-position")||"center bottom",d=c.split(" ")[0],e=c.split(" ")[1],f=document.createElement("div");f.className="akeeba-popover";f.id="akeeba-tooltip-"+b;f.style.display="block";
|
||||
f.className+=" "+c;f.insertAdjacentHTML("afterbegin",'<div class="arrow"></div>');b=document.createElement("div");b.className="akeeba-popover-inner";f.appendChild(b);a.target.hasAttribute("data-original-title")&&(c=document.createElement("h3"),c.className="akeeba-popover-title",c.innerHTML=a.target.getAttribute("data-original-title"),b.appendChild(c));c=document.createElement("div");c.className="akeeba-popover-content";c.innerHTML=a.target.getAttribute("data-content");b.appendChild(c);document.body.appendChild(f);
|
||||
akeeba.Tooltip.positionAt(a.target,f,d,e)}}};akeeba.Tooltip.onMouseLeave=function(a){a.target.hasAttribute("data-tooltip-noclose")||akeeba.Tooltip.hideTooltip(a.target)};akeeba.Tooltip.onClick=function(a){if(a.target.hasAttribute("data-tooltip-uuid"))if(a.target.hasAttribute("data-tooltip-noclose"))a.target.removeAttribute("data-tooltip-noclose");else{var b=a.target.getAttribute("data-tooltip-uuid");null!=document.getElementById("akeeba-tooltip-"+b)&&a.target.setAttribute("data-tooltip-noclose",1)}};
|
||||
akeeba.Tooltip.hideTooltip=function(a){a.hasAttribute("data-tooltip-uuid")&&(a=a.getAttribute("data-tooltip-uuid"),(a=document.getElementById("akeeba-tooltip-"+a))&&document.body.removeChild(a))};
|
||||
akeeba.Tooltip.positionAt=function(a,b,c,d){var e=a.getBoundingClientRect();switch(c){case "left":a=parseInt(e.left)-10-b.offsetWidth;0>parseInt(e.left)-b.offsetWidth&&(a=10);break;case "right":a=e.right+10;parseInt(e.right)+b.offsetWidth>document.documentElement.clientWidth&&(a=document.documentElement.clientWidth-b.offsetWidth-10);break;default:case "center":a=parseInt(e.left)+(a.offsetWidth-b.offsetWidth)/2}switch(d){case "center":d=(parseInt(e.top)+parseInt(e.bottom))/2-b.offsetHeight/2;break;
|
||||
case "bottom":d=parseInt(e.bottom)+10;break;default:case "top":d=parseInt(e.top)-b.offsetHeight-10}a=0>a?parseInt(e.left):a;d=0>d?parseInt(e.bottom)+10:d;b.style.left=a+"px";b.style.top=d+pageYOffset+"px"}; //# sourceMappingURL=Tooltip.map
|
||||
56
media/fef/js/darkmode.js
Normal file
56
media/fef/js/darkmode.js
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*
|
||||
* Created by Crystal Dionysopoulou for Akeeba Ltd, https://www.akeeba.com
|
||||
*/
|
||||
|
||||
if (typeof akeeba === 'undefined')
|
||||
{
|
||||
akeeba = {};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef === 'undefined')
|
||||
{
|
||||
akeeba.fef = {};
|
||||
}
|
||||
|
||||
akeeba.fef.darkMode = function(status)
|
||||
{
|
||||
if (status == null)
|
||||
{
|
||||
status = true;
|
||||
}
|
||||
|
||||
var elNodes = document.querySelectorAll('.akeeba-renderer-fef');
|
||||
|
||||
for (var i = 0; i < elNodes.length; i++) {
|
||||
var elNode = elNodes[i];
|
||||
var currentClasses = elNode.className.split(' ');
|
||||
elNode.className = '';
|
||||
|
||||
for (var j = 0; j < currentClasses.length; j++) {
|
||||
var thisClass = currentClasses[j];
|
||||
|
||||
if (thisClass === 'akeeba-renderer-fef--dark')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
elNode.className += ' ' + thisClass;
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
elNode.className += ' akeeba-renderer-fef--dark';
|
||||
}
|
||||
|
||||
if (elNode.className.trim)
|
||||
{
|
||||
elNode.className = elNode.className.trim();
|
||||
}
|
||||
}
|
||||
};
|
||||
8
media/fef/js/darkmode.min.js
vendored
Normal file
8
media/fef/js/darkmode.min.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};window.akeeba.fef=window.akeeba.fef||{};akeeba.fef.darkMode=function(a){null==a&&(a=!0);a=document.querySelectorAll(".akeeba-renderer-fef");0!==a.length&&akeeba.System.forEach(a,function(c,b){akeeba.System.toggleClass(b,"akeeba-renderer-fef--dark")})}; //# sourceMappingURL=Darkmode.map
|
||||
8
media/fef/js/darkmode.min.map
Normal file
8
media/fef/js/darkmode.min.map
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"version":3,
|
||||
"file":"/Users/nicholas/Projects/akeeba/fef/out/js/darkmode.min.js",
|
||||
"lineCount":1,
|
||||
"mappings":"AAUsB,WAAtB,GAAI,MAAOA,OAAX,GAECA,MAFD,CAEU,EAFV,CAK0B,YAA1B,GAAI,MAAOA,OAAAC,IAAX,GAECD,MAAAC,IAFD,CAEc,EAFd,CAKAD,OAAAC,IAAAC,SAAA,CAAsBC,QAAQ,CAACC,CAAD,CAC9B,CACe,IAAd,EAAIA,CAAJ,GAECA,CAFD,CAEU,CAAA,CAFV,CAOA,KAFA,IAAIC,EAAUC,QAAAC,iBAAA,CAA0B,sBAA1B,CAAd,CAESC,EAAI,CAAb,CAAgBA,CAAhB,CAAoBH,CAAAI,OAApB,CAAoCD,CAAA,EAApC,CAAyC,CACxC,IAAIE,EAASL,CAAA,CAAQG,CAAR,CAAb,CACIG,EAAiBD,CAAAE,UAAAC,MAAA,CAAuB,GAAvB,CACrBH,EAAAE,UAAA,CAAmB,EAEnB,KAAK,IAAIE,EAAI,CAAb,CAAgBA,CAAhB,CAAoBH,CAAAF,OAApB,CAA2CK,CAAA,EAA3C,CAAgD,CAC/C,IAAIC,EAAYJ,CAAA,CAAeG,CAAf,CAEE,4BAAlB,GAAIC,CAAJ,GAKAL,CAAAE,UALA,EAKoB,GALpB,CAK0BG,CAL1B,CAH+C,CAW5CX,CAAJ,GAECM,CAAAE,UAFD,EAEqB,4BAFrB,CAKIF,EAAAE,UAAAI,KAAJ,GAECN,CAAAE,UAFD,CAEoBF,CAAAE,UAAAI,KAAA,EAFpB,CArBwC,CAR1C;",
|
||||
"sources":["/Users/nicholas/Projects/akeeba/fef/out/js/darkmode.js"],
|
||||
"names":["akeeba","fef","darkMode","akeeba.fef.darkMode","status","elNodes","document","querySelectorAll","i","length","elNode","currentClasses","className","split","j","thisClass","trim"]
|
||||
}
|
||||
11
media/fef/js/dependencies.json
Normal file
11
media/fef/js/dependencies.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"Ajax": [],
|
||||
"Darkmode": ["System"],
|
||||
"Dropdown": ["System"],
|
||||
"Loader": [],
|
||||
"Menu": [],
|
||||
"Modal": [],
|
||||
"System": ["Loader", "Ajax", "Modal"],
|
||||
"Tabs": ["System"],
|
||||
"Tooltip": ["System"]
|
||||
}
|
||||
205
media/fef/js/dropdown.js
Normal file
205
media/fef/js/dropdown.js
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*
|
||||
* Created by Crystal Dionysopoulou for Akeeba Ltd, https://www.akeeba.com
|
||||
*/
|
||||
|
||||
if (typeof akeeba === 'undefined')
|
||||
{
|
||||
akeeba = {};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef === 'undefined')
|
||||
{
|
||||
akeeba.fef = {};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef.forEach === 'undefined')
|
||||
{
|
||||
akeeba.fef.forEach = function (array, callback, scope) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
callback.call(scope, i, array[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef.triggerEvent === 'undefined')
|
||||
{
|
||||
akeeba.fef.triggerEvent = function (element, eventName)
|
||||
{
|
||||
if (typeof element === 'undefined')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (element === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow the passing of an element ID string instead of the DOM elem
|
||||
if (typeof element === "string")
|
||||
{
|
||||
element = document.getElementById(element);
|
||||
}
|
||||
|
||||
if (typeof element !== 'object')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(element instanceof Element))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Use jQuery and be done with it!
|
||||
if (typeof window.jQuery === 'function')
|
||||
{
|
||||
window.jQuery(element).trigger(eventName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Internet Explorer way
|
||||
if (document.fireEvent && (typeof window.Event === 'undefined'))
|
||||
{
|
||||
element.fireEvent('on' + eventName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This works on Chrome and Edge but not on Firefox. Ugh.
|
||||
var event = null;
|
||||
|
||||
event = document.createEvent("Event");
|
||||
event.initEvent(eventName, true, true);
|
||||
element.dispatchEvent(event);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the dropdown interface for specific HTML elements
|
||||
*
|
||||
* @param {String} [selector] CSS selector for the tab-set wrapper(s). Default: 'nav.akeeba-dropdown'
|
||||
*/
|
||||
akeeba.fef.dropdown = function(selector)
|
||||
{
|
||||
// Use the default selector, if necessary
|
||||
if ((typeof selector === 'undefined') || (selector === ''))
|
||||
{
|
||||
selector = 'nav.akeeba-dropdown';
|
||||
}
|
||||
|
||||
// Get all outer wrappers (NAV elements)
|
||||
var navList = document.querySelectorAll(selector);
|
||||
|
||||
if (navList.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop for the first button inside each wrapper (the NAV)
|
||||
akeeba.fef.forEach(navList, function(i, elNav) {
|
||||
// Get the first button inside the NAV wrapper. That's our drop-down toggle.
|
||||
var buttonList = elNav.querySelectorAll('button');
|
||||
|
||||
if (buttonList.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var elButton = buttonList[0];
|
||||
|
||||
// Add an event listener to toggle the "open" class whenever the button is clicked.
|
||||
elButton.addEventListener('click', function (event) {
|
||||
var isOpen = false;
|
||||
var currentClasses = this.className.split(' ');
|
||||
var newClass = '';
|
||||
|
||||
for (var property in currentClasses)
|
||||
{
|
||||
if (!currentClasses.hasOwnProperty(property))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentClasses[property] === 'open')
|
||||
{
|
||||
isOpen = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
newClass += currentClasses[property] + ' ';
|
||||
}
|
||||
|
||||
if (newClass.trim)
|
||||
{
|
||||
newClass = newClass.trim();
|
||||
}
|
||||
|
||||
if (!isOpen)
|
||||
{
|
||||
newClass += ' open';
|
||||
}
|
||||
|
||||
this.className = newClass;
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Loop through all section > a elements in the NAV
|
||||
var linkList = elNav.querySelectorAll('section > a');
|
||||
|
||||
if (linkList.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicking on each link will do two things:
|
||||
* - It will set the clicked link's class to “current”
|
||||
* - It will unset the “current” class on every other link
|
||||
* - It will trigger a virtual click on the drop-down button (to close the drop-down).
|
||||
*/
|
||||
akeeba.fef.forEach(linkList, function(i, elLink) {
|
||||
elLink.addEventListener('click', function (event) {
|
||||
// Close the drop-down
|
||||
akeeba.fef.triggerEvent(elButton, 'click');
|
||||
|
||||
// Remove the “current” class from all links
|
||||
akeeba.fef.forEach(linkList, function(i, element) {
|
||||
var currentClasses = element.className.split(' ');
|
||||
var newClass = '';
|
||||
|
||||
for (var property in currentClasses)
|
||||
{
|
||||
if (!currentClasses.hasOwnProperty(property) || (currentClasses[property] === 'current'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newClass += currentClasses[property] + ' ';
|
||||
}
|
||||
|
||||
if (newClass.trim)
|
||||
{
|
||||
newClass = newClass.trim();
|
||||
}
|
||||
|
||||
element.className = newClass;
|
||||
});
|
||||
|
||||
// Add the “current” class to the current link
|
||||
this.className += ' current';
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
10
media/fef/js/dropdown.min.js
vendored
Normal file
10
media/fef/js/dropdown.min.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};window.akeeba.fef=window.akeeba.fef||{};
|
||||
akeeba.fef.dropdown=function(a){if("undefined"===typeof a||""===a)a="nav.akeeba-dropdown";a=document.querySelectorAll(a);0!==a.length&&akeeba.System.forEach(a,function(b,d){b=d.querySelectorAll("button");if(0!==b.length){var e=b[0];e.addEventListener("click",function(f){akeeba.System.toggleClass(this,"open");f.preventDefault()});var c=d.querySelectorAll("section > a");0!==c.length&&akeeba.System.forEach(c,function(f,g){g.addEventListener("click",function(h){akeeba.System.triggerEvent(e,"click");akeeba.System.forEach(c,
|
||||
function(l,k){akeeba.System.removeClass(k,"current")});akeeba.System.addClass(this,"current");h.preventDefault()})})}})}; //# sourceMappingURL=Dropdown.map
|
||||
8
media/fef/js/dropdown.min.map
Normal file
8
media/fef/js/dropdown.min.map
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"version":3,
|
||||
"file":"/Users/nicholas/Projects/akeeba/fef/out/js/dropdown.min.js",
|
||||
"lineCount":4,
|
||||
"mappings":"AAUsB,WAAtB,GAAI,MAAOA,OAAX,GAEIA,MAFJ,CAEa,EAFb,CAK0B,YAA1B,GAAI,MAAOA,OAAAC,IAAX,GAEID,MAAAC,IAFJ,CAEiB,EAFjB,CAKkC,YAAlC,GAAI,MAAOD,OAAAC,IAAAC,QAAX,GAECF,MAAAC,IAAAC,QAFD,CAEsBC,QAAS,CAACC,CAAD,CAAQC,CAAR,CAAkBC,CAAlB,CAAyB,CACtD,IAAK,IAAIC,EAAI,CAAb,CAAgBA,CAAhB,CAAoBH,CAAAI,OAApB,CAAkCD,CAAA,EAAlC,CACCF,CAAAI,KAAA,CAAcH,CAAd,CAAqBC,CAArB,CAAwBH,CAAA,CAAMG,CAAN,CAAxB,CAFqD,CAFxD,CASuC;WAAvC,GAAI,MAAOP,OAAAC,IAAAS,aAAX,GAECV,MAAAC,IAAAS,aAFD,CAE2BC,QAAS,CAACC,CAAD,CAAUC,CAAV,CACnC,CACC,GAAuB,WAAvB,GAAI,MAAOD,EAAX,EAKgB,IALhB,GAKIA,CALJ,GAWuB,QAKnB,GALA,MAAOA,EAKP,GAHHA,CAGG,CAHOE,QAAAC,eAAA,CAAwBH,CAAxB,CAGP,EAAmB,QAAnB,GAAA,MAAOA,EAAP,EAKEA,CALF,WAKqBI,QArBzB,EA2BA,GAA6B,UAA7B,GAAI,MAAOC,OAAAC,OAAX,CAECD,MAAAC,OAAA,CAAcN,CAAd,CAAAO,QAAA,CAA+BN,CAA/B,CAFD,KAQA,IAAIC,QAAAM,UAAJ,EAAmD,WAAnD,GAA2B,MAAOH,OAAAI,MAAlC,CAECT,CAAAQ,UAAA,CAAkB,IAAlB,CAAyBP,CAAzB,CAFD,KAAA,CAUA,IAAAS,EAAQR,QAAAS,YAAA,CAAqB,OAArB,CACRD,EAAAE,UAAA,CAAgBX,CAAhB,CAA2B,CAAA,CAA3B,CAAiC,CAAA,CAAjC,CACAD,EAAAa,cAAA,CAAsBH,CAAtB,CAZA,CApCD,CAHD,CA4DAtB;MAAAC,IAAAyB,SAAA,CAAsBC,QAAQ,CAACC,CAAD,CAC9B,CAEI,GAAyB,WAAzB,GAAK,MAAOA,EAAZ,EAAuD,EAAvD,GAA0CA,CAA1C,CAEIA,CAAA,CAAW,qBAIXC,EAAAA,CAAUf,QAAAgB,iBAAA,CAA0BF,CAA1B,CAES,EAAvB,GAAIC,CAAArB,OAAJ,EAMAR,MAAAC,IAAAC,QAAA,CAAmB2B,CAAnB,CAA4B,QAAQ,CAACtB,CAAD,CAAIwB,CAAJ,CAAW,CAEvCC,CAAAA,CAAaD,CAAAD,iBAAA,CAAuB,QAAvB,CAEjB,IAA0B,CAA1B,GAAIE,CAAAxB,OAAJ,CAAA,CAKA,IAAIyB,EAAWD,CAAA,CAAW,CAAX,CAGrBC,EAAAC,iBAAA,CAA0B,OAA1B,CAAmC,QAAS,CAACZ,CAAD,CAAQ,CAChD,IAAIa,EAAS,CAAA,CAAb,CACCC,EAAiB,IAAAC,UAAAC,MAAA,CAAqB,GAArB,CADlB,CAECC,EAAW,EAFZ,CAIMC,CAAT,KAASA,CAAT,GAAqBJ,EAArB,CAEMA,CAAAK,eAAA,CAA8BD,CAA9B,CAAL,GAK6C,MAAjC,GAAIJ,CAAA,CAAeI,CAAf,CAAJ,CAEIL,CAFJ,CAEa,CAAA,CAFb,CAOZI,CAPY,EAOAH,CAAA,CAAeI,CAAf,CAPA,CAO2B,GAZvC,CAeGD,EAAAG,KAAJ,GAECH,CAFD,CAEYA,CAAAG,KAAA,EAFZ,CAKKP,EAAL,GAEaI,CAFb,EAEyB,OAFzB,CAKA,KAAAF,UAAA,CAAiBE,CAEjBjB,EAAAqB,eAAA,EAlCmD,CAApD,CAsCM,KAAIC,EAAWb,CAAAD,iBAAA,CAAuB,aAAvB,CAES,EAAxB,GAAIc,CAAApC,OAAJ;AAWNR,MAAAC,IAAAC,QAAA,CAAmB0C,CAAnB,CAA6B,QAAQ,CAACrC,CAAD,CAAIsC,CAAJ,CAAY,CAChDA,CAAAX,iBAAA,CAAwB,OAAxB,CAAiC,QAAS,CAACZ,CAAD,CAAQ,CAEjDtB,MAAAC,IAAAS,aAAA,CAAwBuB,CAAxB,CAAkC,OAAlC,CAGAjC,OAAAC,IAAAC,QAAA,CAAmB0C,CAAnB,CAA6B,QAAQ,CAACrC,CAAD,CAAIK,CAAJ,CAAa,CAC7CwB,CAAAA,CAAiBxB,CAAAyB,UAAAC,MAAA,CAAwB,GAAxB,CACrB,KAAIC,EAAW,EAAf,CAESC,CAAT,KAASA,CAAT,GAAqBJ,EAArB,CAEMA,CAAAK,eAAA,CAA8BD,CAA9B,CAAL,EAA8E,SAA9E,GAAiDJ,CAAA,CAAeI,CAAf,CAAjD,GAKAD,CALA,EAKYH,CAAA,CAAeI,CAAf,CALZ,CAKuC,GALvC,CAQGD,EAAAG,KAAJ,GAECH,CAFD,CAEYA,CAAAG,KAAA,EAFZ,CAKA9B,EAAAyB,UAAA,CAAoBE,CAnB6B,CAAlD,CAuBA,KAAAF,UAAA,EAAkB,UAElBf,EAAAqB,eAAA,EA9BiD,CAAlD,CADgD,CAAjD,CA3DM,CAJ2C,CAA/C,CAhBJ;",
|
||||
"sources":["/Users/nicholas/Projects/akeeba/fef/out/js/dropdown.js"],
|
||||
"names":["akeeba","fef","forEach","akeeba.fef.forEach","array","callback","scope","i","length","call","triggerEvent","akeeba.fef.triggerEvent","element","eventName","document","getElementById","Element","window","jQuery","trigger","fireEvent","Event","event","createEvent","initEvent","dispatchEvent","dropdown","akeeba.fef.dropdown","selector","navList","querySelectorAll","elNav","buttonList","elButton","addEventListener","isOpen","currentClasses","className","split","newClass","property","hasOwnProperty","trim","preventDefault","linkList","elLink"]
|
||||
}
|
||||
10
media/fef/js/loader.min.js
vendored
Normal file
10
media/fef/js/loader.min.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};
|
||||
(function(h,r){function m(){n=!0;p()}function p(){n&&null===f&&(f=setInterval(t,200))}function q(a){a=a.split(".");for(var b=window,c=0;c<a.length;c++){if("object"!==typeof b||"undefined"===typeof b[a[c]])return!1;b=b[a[c]]}return!0}function t(){if(!k)if(d.length){k=!0;for(var a=[],b=0;b<d.length;b++){var c=d[b],e=c[0];c=c[1];if("string"===typeof e)var g=q(e);else{g=!0;for(var l=0;l<e.length;l++)g=g&&q(e[l])}g?c():a[a.length]=[e,c]}d=a;k=!1}else clearInterval(f),f=null}var n=!1,d=[],f=null,k=!1;h.Loader=
|
||||
h.Loader||{};h.Loader.add=function(a,b){d[d.length]=[a,b];p()};r.addEventListener("DOMContentLoaded",m,!1);window.addEventListener("load",m,!1)})(akeeba,document); //# sourceMappingURL=Loader.map
|
||||
50
media/fef/js/menu.js
Normal file
50
media/fef/js/menu.js
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*
|
||||
* Created by Crystal Dionysopoulou for Akeeba Ltd, https://www.akeeba.com
|
||||
*/
|
||||
|
||||
if (typeof akeeba === 'undefined')
|
||||
{
|
||||
akeeba = {};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef === 'undefined')
|
||||
{
|
||||
akeeba.fef = {};
|
||||
}
|
||||
|
||||
akeeba.fef.menuButton = function(selector)
|
||||
{
|
||||
// Use the default selector, if necessary
|
||||
if ((typeof selector === 'undefined') || (selector === ''))
|
||||
{
|
||||
selector = 'a.akeeba-menu-button';
|
||||
}
|
||||
|
||||
var menuButtonsList = document.querySelectorAll(selector);
|
||||
|
||||
if (menuButtonsList.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
menuButtonsList.forEach(function(elButton) {
|
||||
elButton.addEventListener('click', function(event) {
|
||||
var elNav = elButton.parentElement.parentElement.querySelector('nav');
|
||||
|
||||
if (elNav.style.display !== 'flex')
|
||||
{
|
||||
elNav.style.display = 'flex';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
elNav.style.display = null;
|
||||
});
|
||||
});
|
||||
};
|
||||
8
media/fef/js/menu.min.js
vendored
Normal file
8
media/fef/js/menu.min.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};window.akeeba.fef=window.akeeba.fef||{};akeeba.fef.menuButton=function(a){if("undefined"===typeof a||""===a)a="a.akeeba-menu-button";a=document.querySelectorAll(a);0!==a.length&&a.forEach(function(c){c.addEventListener("click",function(b){b=c.parentElement.parentElement.querySelector("nav");b.style.display="flex"!==b.style.display?"flex":null})})}; //# sourceMappingURL=Menu.map
|
||||
8
media/fef/js/menu.min.map
Normal file
8
media/fef/js/menu.min.map
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"version":3,
|
||||
"file":"/Users/nicholas/Projects/akeeba/fef/out/js/menu.min.js",
|
||||
"lineCount":1,
|
||||
"mappings":"AAUsB,WAAtB,GAAI,MAAOA,OAAX,GAEIA,MAFJ,CAEa,EAFb,CAK0B,YAA1B,GAAI,MAAOA,OAAAC,IAAX,GAEID,MAAAC,IAFJ,CAEiB,EAFjB,CAKAD,OAAAC,IAAAC,WAAA,CAAwBC,QAAQ,CAACC,CAAD,CAChC,CAEI,GAAyB,WAAzB,GAAK,MAAOA,EAAZ,EAAuD,EAAvD,GAA0CA,CAA1C,CAEIA,CAAA,CAAW,sBAGXC,EAAAA,CAAkBC,QAAAC,iBAAA,CAA0BH,CAA1B,CAES,EAA/B,GAAIC,CAAAG,OAAJ,EAKAH,CAAAI,QAAA,CAAwB,QAAQ,CAACC,CAAD,CAAW,CACvCA,CAAAC,iBAAA,CAA0B,OAA1B,CAAmC,QAAQ,CAACC,CAAD,CAAQ,CAC3CC,CAAAA,CAAQH,CAAAI,cAAAA,cAAAC,cAAA,CAAmD,KAAnD,CAIRF,EAAAG,MAAAC,QAAA,CAFwB,MAA5B,GAAIJ,CAAAG,MAAAC,QAAJ,CAE0B,MAF1B,CAOsB,IAVyB,CAAnD,CADuC,CAA3C,CAdJ;",
|
||||
"sources":["/Users/nicholas/Projects/akeeba/fef/out/js/menu.js"],
|
||||
"names":["akeeba","fef","menuButton","akeeba.fef.menuButton","selector","menuButtonsList","document","querySelectorAll","length","forEach","elButton","addEventListener","event","elNav","parentElement","querySelector","style","display"]
|
||||
}
|
||||
128
media/fef/js/tabs.js
Normal file
128
media/fef/js/tabs.js
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*
|
||||
* Created by Crystal Dionysopoulou for Akeeba Ltd, https://www.akeeba.com
|
||||
*/
|
||||
|
||||
if (typeof akeeba === 'undefined')
|
||||
{
|
||||
akeeba = {};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef === 'undefined')
|
||||
{
|
||||
akeeba.fef = {};
|
||||
}
|
||||
|
||||
if (typeof akeeba.fef.forEach === 'undefined')
|
||||
{
|
||||
akeeba.fef.forEach = function (array, callback, scope) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
callback.call(scope, i, array[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the tab interface for specific HTML elements
|
||||
*
|
||||
* @param {String} [selector] CSS selector for the tab-set wrapper(s). Default: 'div.akeeba-tabs'
|
||||
*/
|
||||
akeeba.fef.tabs = function(selector)
|
||||
{
|
||||
// Use the default selector, if necessary
|
||||
if ((typeof selector === 'undefined') || (selector === ''))
|
||||
{
|
||||
selector = 'div.akeeba-tabs';
|
||||
}
|
||||
|
||||
var wrappersList = document.querySelectorAll(selector);
|
||||
|
||||
if (wrappersList.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop for every tab set matching the selector
|
||||
akeeba.fef.forEach(wrappersList, function(i, elWrapper) {
|
||||
// Sort the child elements of the selector to tabs (label) and panels (section)
|
||||
var tabList = elWrapper.querySelectorAll('label');
|
||||
var tabId = elWrapper.id;
|
||||
var tabPreselected = '';
|
||||
|
||||
if (tabList.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (tabId != '')
|
||||
{
|
||||
tabPreselected = window.sessionStorage.getItem('akeeba.tabs.' + tabId);
|
||||
}
|
||||
|
||||
akeeba.fef.forEach(tabList, function(k, elTab) {
|
||||
if (elTab.parentElement !== elWrapper)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
elTab.addEventListener('click', function (event) {
|
||||
var selectedId = this.getAttribute('for');
|
||||
|
||||
akeeba.fef.forEach(tabList, function(q, element) {
|
||||
if (element.parentElement !== elWrapper)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var currentClasses = element.className.split(' ');
|
||||
var newClass = '';
|
||||
|
||||
for (var property in currentClasses)
|
||||
{
|
||||
if (!currentClasses.hasOwnProperty(property) || (currentClasses[property] === 'active'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newClass += currentClasses[property] + ' ';
|
||||
}
|
||||
|
||||
if (newClass.trim)
|
||||
{
|
||||
newClass = newClass.trim();
|
||||
}
|
||||
|
||||
// If the 'for' attribute matches add back the "active" class
|
||||
if (element.getAttribute('for') === selectedId)
|
||||
{
|
||||
window.sessionStorage.setItem('akeeba.tabs.' + tabId, selectedId);
|
||||
newClass += ' active';
|
||||
}
|
||||
|
||||
element.className = newClass;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (tabPreselected != '')
|
||||
{
|
||||
akeeba.fef.forEach(tabList, function(k, elTab) {
|
||||
if (elTab.parentElement !== elWrapper)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (elTab.getAttribute('for') == tabPreselected)
|
||||
{
|
||||
var clickEvent = new MouseEvent('click');
|
||||
elTab.dispatchEvent(clickEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
10
media/fef/js/tabs.min.js
vendored
Normal file
10
media/fef/js/tabs.min.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
Akeeba Frontend Framework (FEF)
|
||||
|
||||
@package fef
|
||||
@copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
@license GNU General Public License version 3, or later
|
||||
*/
|
||||
window.akeeba=window.akeeba||{};window.akeeba.fef=window.akeeba.fef||{};
|
||||
akeeba.fef.tabs=function(a){if("undefined"===typeof a||""===a)a="div.akeeba-tabs";a=document.querySelectorAll(a);0!==a.length&&akeeba.System.forEach(a,function(l,c){var d=c.querySelectorAll("label"),f=c.id,g="";0!==d.length&&(""!=f&&(g=window.sessionStorage.getItem("akeeba.tabs."+f)),akeeba.System.forEach(d,function(k,b){b.parentElement===c&&b.addEventListener("click",function(m){var h=this.getAttribute("for");akeeba.System.forEach(d,function(n,e){e.parentElement===c&&(e.getAttribute("for")===h?(window.sessionStorage.setItem("akeeba.tabs."+
|
||||
f,h),akeeba.System.addClass(e,"active")):akeeba.System.removeClass(e,"active"))})})}),""!=g&&akeeba.System.forEach(d,function(k,b){b.parentElement===c&&b.getAttribute("for")===g&&akeeba.System.triggerEvent(b,"click")}))})}; //# sourceMappingURL=Tabs.map
|
||||
8
media/fef/js/tabs.min.map
Normal file
8
media/fef/js/tabs.min.map
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"version":3,
|
||||
"file":"/Users/nicholas/Projects/akeeba/fef/out/js/tabs.min.js",
|
||||
"lineCount":3,
|
||||
"mappings":"AAUsB,WAAtB,GAAI,MAAOA,OAAX,GAEIA,MAFJ,CAEa,EAFb,CAK0B,YAA1B,GAAI,MAAOA,OAAAC,IAAX,GAEID,MAAAC,IAFJ,CAEiB,EAFjB,CAKkC,YAAlC,GAAI,MAAOD,OAAAC,IAAAC,QAAX,GAECF,MAAAC,IAAAC,QAFD,CAEsBC,QAAS,CAACC,CAAD,CAAQC,CAAR,CAAkBC,CAAlB,CAAyB,CACtD,IAAK,IAAIC,EAAI,CAAb,CAAgBA,CAAhB,CAAoBH,CAAAI,OAApB,CAAkCD,CAAA,EAAlC,CACCF,CAAAI,KAAA,CAAcH,CAAd,CAAqBC,CAArB,CAAwBH,CAAA,CAAMG,CAAN,CAAxB,CAFqD,CAFxD,CAcAP;MAAAC,IAAAS,KAAA,CAAkBC,QAAQ,CAACC,CAAD,CAC1B,CAEI,GAAyB,WAAzB,GAAK,MAAOA,EAAZ,EAAuD,EAAvD,GAA0CA,CAA1C,CAEIA,CAAA,CAAW,iBAGXC,EAAAA,CAAeC,QAAAC,iBAAA,CAA0BH,CAA1B,CAES,EAA5B,GAAIC,CAAAL,OAAJ,EAMAR,MAAAC,IAAAC,QAAA,CAAmBW,CAAnB,CAAiC,QAAQ,CAACN,CAAD,CAAIS,CAAJ,CAAe,CAEpD,IAAIC,EAAUD,CAAAD,iBAAA,CAA2B,OAA3B,CAAd,CACIG,EAAQF,CAAAG,GADZ,CAEIC,EAAiB,EAEE,EAAvB,GAAIH,CAAAT,OAAJ,GAKa,EAkDnB,EAlDUU,CAkDV,GAhDUE,CAgDV,CAhD2BC,MAAAC,eAAAC,QAAA,CAA8B,cAA9B,CAA+CL,CAA/C,CAgD3B,EA7CMlB,MAAAC,IAAAC,QAAA,CAAmBe,CAAnB,CAA4B,QAAQ,CAACO,CAAD,CAAIC,CAAJ,CAAW,CACvCA,CAAAC,cAAJ,GAA4BV,CAA5B,EAKAS,CAAAE,iBAAA,CAAuB,OAAvB,CAAgC,QAAS,CAACC,CAAD,CAAQ,CAC7C,IAAIC,EAAa,IAAAC,aAAA,CAAkB,KAAlB,CAEjB9B,OAAAC,IAAAC,QAAA,CAAmBe,CAAnB,CAA4B,QAAQ,CAACc,CAAD,CAAIC,CAAJ,CAAa,CAC7C,GAAIA,CAAAN,cAAJ,GAA8BV,CAA9B,CAAA,CAKIiB,CAAAA,CAAiBD,CAAAE,UAAAC,MAAA,CAAwB,GAAxB,CACrB,KAAIC,EAAW,EAAf;AAESC,CAAT,KAASA,CAAT,GAAqBJ,EAArB,CAESA,CAAAK,eAAA,CAA8BD,CAA9B,CAAL,EAA8E,QAA9E,GAAiDJ,CAAA,CAAeI,CAAf,CAAjD,GAKAD,CALA,EAKYH,CAAA,CAAeI,CAAf,CALZ,CAKuC,GALvC,CAQAD,EAAAG,KAAJ,GAEIH,CAFJ,CAEeA,CAAAG,KAAA,EAFf,CAMIP,EAAAF,aAAA,CAAqB,KAArB,CAAJ,GAAoCD,CAApC,GAEdR,MAAAC,eAAAkB,QAAA,CAA8B,cAA9B,CAA+CtB,CAA/C,CAAsDW,CAAtD,CACkB,CAAAO,CAAA,EAAY,SAHhB,CAMAJ,EAAAE,UAAA,CAAoBE,CA9BpB,CAD6C,CAAjD,CAH6C,CAAjD,CAN2C,CAA/C,CA6CN,CAAsB,EAAtB,EAAIhB,CAAJ,EAECpB,MAAAC,IAAAC,QAAA,CAAmBe,CAAnB,CAA4B,QAAQ,CAACO,CAAD,CAAIC,CAAJ,CAAW,CAC1CA,CAAAC,cAAJ,GAA4BV,CAA5B,EAKIS,CAAAK,aAAA,CAAmB,KAAnB,CALJ,EAKiCV,CALjC,GAOKqB,CACJ,CADiB,IAAIC,UAAJ,CAAe,OAAf,CACjB,CAAAjB,CAAAkB,cAAA,CAAoBF,CAApB,CARD,CAD8C,CAA/C,CAzDK,CANoD,CAAxD,CAfJ;",
|
||||
"sources":["/Users/nicholas/Projects/akeeba/fef/out/js/tabs.js"],
|
||||
"names":["akeeba","fef","forEach","akeeba.fef.forEach","array","callback","scope","i","length","call","tabs","akeeba.fef.tabs","selector","wrappersList","document","querySelectorAll","elWrapper","tabList","tabId","id","tabPreselected","window","sessionStorage","getItem","k","elTab","parentElement","addEventListener","event","selectedId","getAttribute","q","element","currentClasses","className","split","newClass","property","hasOwnProperty","trim","setItem","clickEvent","MouseEvent","dispatchEvent"]
|
||||
}
|
||||
316
media/fef/php/AkeebaFEFLoader.php
Normal file
316
media/fef/php/AkeebaFEFLoader.php
Normal file
@ -0,0 +1,316 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Loads Akeeba FEF CSS and JavaScript files. Cross-platform.
|
||||
*/
|
||||
class AkeebaFEFLoader
|
||||
{
|
||||
/**
|
||||
* Script dependencies, as loaded from dependencies.json
|
||||
*
|
||||
* @var array
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $dependenciesCache = [];
|
||||
|
||||
/**
|
||||
* Is the Akeeba FEF CSS Framework already loaded?
|
||||
*
|
||||
* @var bool
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $loadedCSSFramework = false;
|
||||
|
||||
/**
|
||||
* Is the Akeeba FEF JavaScript Framework already loaded?
|
||||
*
|
||||
* 0: no; 1: minimal; 2: full
|
||||
*
|
||||
* @var int
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $loadedJSFramework = 0;
|
||||
|
||||
/**
|
||||
* The platform-specific callback for loading an FEF CSS file given its basename.
|
||||
*
|
||||
* @var callable
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $cssLoaderCallback;
|
||||
|
||||
/**
|
||||
* The platform-specific callback for loading an FEF JavaScript file given its basename.
|
||||
*
|
||||
* @var callable
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $jsLoaderCallback;
|
||||
|
||||
/**
|
||||
* The platform we are currently running under. Auto-detected if not set.
|
||||
*
|
||||
* @var null|string
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $platform;
|
||||
|
||||
/**
|
||||
* Records the FEF JS files which have already been loaded.
|
||||
*
|
||||
* @var array
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private $loadedScripts = [];
|
||||
|
||||
public function __construct(callable $cssLoaderCallback, callable $jsLoaderCallback, ?string $platform)
|
||||
{
|
||||
$this->cssLoaderCallback = $cssLoaderCallback;
|
||||
$this->jsLoaderCallback = $jsLoaderCallback;
|
||||
$this->platform = $platform ?? $this->getPlatform();
|
||||
|
||||
if (!in_array($this->platform, ['joomla', 'wordpress', 'standalone']))
|
||||
{
|
||||
$this->platform = $this->getPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the Akeeba Frontend Framework, both CSS and JS
|
||||
*
|
||||
* @param bool $withReset Should I also load the CSS reset for the FEF container? (Only applies to Joomla)
|
||||
* @param bool $dark Include Dark Mode CSS?
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.3
|
||||
*/
|
||||
public function loadCSSFramework(bool $withReset = true, bool $dark = false)
|
||||
{
|
||||
if ($this->loadedCSSFramework)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loadedCSSFramework = true;
|
||||
|
||||
if ($withReset && ($this->platform === 'joomla'))
|
||||
{
|
||||
call_user_func($this->cssLoaderCallback, 'fef-reset');
|
||||
}
|
||||
|
||||
call_user_func($this->cssLoaderCallback, 'fef-' . $this->platform);
|
||||
|
||||
if ($dark)
|
||||
{
|
||||
call_user_func($this->cssLoaderCallback, 'dark');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the Akeeba FEF JavaScript Framework
|
||||
*
|
||||
* @param bool $minimal Should I load the minimal framework (without optional features linked to FEF CSS?)
|
||||
*
|
||||
* @return void
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public function loadJSFramework(bool $minimal = false): void
|
||||
{
|
||||
$requested = $minimal ? 1 : 2;
|
||||
|
||||
if ($this->loadedJSFramework >= $requested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Should I load Akeeba.Loader? Check performed before I change the loadedJSFramework value.
|
||||
$initLoader = $this->loadedJSFramework === 0;
|
||||
|
||||
// Update $this->loadedJSFramework so that loadFEFScript actually loads the scripts we tell it!
|
||||
$this->loadedJSFramework = $requested;
|
||||
|
||||
// Always load the Akeeba.Loader script first.
|
||||
if ($initLoader)
|
||||
{
|
||||
$this->loadFEFScript('Loader', false);
|
||||
}
|
||||
|
||||
if ($requested === 1)
|
||||
{
|
||||
// Minimal framework: only load System
|
||||
$this->loadFEFScript('System');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Full framework. Load the core FEF scripts. This pulls in System and its dependencies.
|
||||
if ($this->platform !== 'joomla')
|
||||
{
|
||||
$this->loadFEFScript('Menu');
|
||||
}
|
||||
|
||||
$this->loadFEFScript('Tabs');
|
||||
$this->loadFEFScript('Dropdown');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Akeeba FEF been already loaded?
|
||||
*
|
||||
* @return bool
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public function isLoadedCSSFramework(): bool
|
||||
{
|
||||
return $this->isLoadedCSSFramework();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an Akeeba FEF JavaScript file and its dependencies.
|
||||
*
|
||||
* @param string $name The basename of the file, e.g. "Tabs"
|
||||
* @param bool $defer Should I defer loading of the file?
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public function loadFEFScript(string $name, bool $defer = true): void
|
||||
{
|
||||
// Make sure FEF is loaded at all
|
||||
if (!$this->loadedJSFramework)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the script is already loaded return early.
|
||||
if (in_array($name, $this->loadedScripts))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loadedScripts[] = $name;
|
||||
|
||||
// Never defer loading for the Akeeba.Loader
|
||||
$defer = $defer && ($name !== 'Loader');
|
||||
|
||||
// Try to find the requested file
|
||||
$testFile = sprintf("%s/../js/%s.min.js", __DIR__, $name);
|
||||
|
||||
if (!@is_file($testFile))
|
||||
{
|
||||
// Did someone use the legacy name of a JS file?
|
||||
$name = ucfirst($name);
|
||||
$testFile = sprintf("%s/../js/%s.min.js", __DIR__, $name);
|
||||
}
|
||||
|
||||
if (!@is_file($testFile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Load any dependencies before the script itself
|
||||
$dependencies = $this->getDependencies($name);
|
||||
|
||||
foreach ($dependencies as $dependency)
|
||||
{
|
||||
$this->loadFEFScript($dependency);
|
||||
}
|
||||
|
||||
// Use the platform-specific callback to actually load the script
|
||||
call_user_func($this->jsLoaderCallback, $name, $defer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the auto-detected platform FEF is running under: joomla, wordpress or standalone.
|
||||
*
|
||||
* @return string
|
||||
* @since 2.0.0
|
||||
* @see self::setPlatform
|
||||
*/
|
||||
private function getPlatform(): string
|
||||
{
|
||||
if (defined('_JEXEC'))
|
||||
{
|
||||
return 'joomla';
|
||||
}
|
||||
|
||||
if (defined('WPINC'))
|
||||
{
|
||||
return 'wordpress';
|
||||
}
|
||||
|
||||
return 'standalone';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dependencies of an FEF script
|
||||
*
|
||||
* @param string $script
|
||||
*
|
||||
* @return array
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private function getDependencies(string $script): array
|
||||
{
|
||||
if (empty($this->dependenciesCache))
|
||||
{
|
||||
self::loadDependencies();
|
||||
}
|
||||
|
||||
$dependencies = $this->dependenciesCache[$script] ?? [];
|
||||
|
||||
return is_array($dependencies) ? $dependencies : [$dependencies];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the FEF script dependencies
|
||||
*
|
||||
* @return void
|
||||
* @since 2.0.0
|
||||
*/
|
||||
private function loadDependencies(): void
|
||||
{
|
||||
// Reset the dependencies cache
|
||||
$this->dependenciesCache = [];
|
||||
|
||||
// Make sure dependencies.json exists
|
||||
$sourceFile = __DIR__ . '/../js/dependencies.json';
|
||||
|
||||
if (!@file_exists($sourceFile) || !@is_file($sourceFile) || !@is_readable($sourceFile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load the JSON file contents
|
||||
$dependenciesJSON = @file_get_contents($sourceFile);
|
||||
|
||||
if (($dependenciesJSON === false) || empty(trim($dependenciesJSON)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to decode the JSON file
|
||||
try
|
||||
{
|
||||
$this->dependenciesCache = @json_decode($dependenciesJSON, true, 512);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$this->dependenciesCache = null;
|
||||
}
|
||||
|
||||
// Make sure the dependencies cache is an array
|
||||
$this->dependenciesCache = $this->dependenciesCache ?? [];
|
||||
|
||||
if (!is_array($this->dependenciesCache))
|
||||
{
|
||||
$this->dependenciesCache = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
562
media/fef/script.fef.php
Normal file
562
media/fef/script.fef.php
Normal file
@ -0,0 +1,562 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
use Joomla\CMS\Date\Date as JDate;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\CMS\Installer\Adapter\FileAdapter as JInstallerAdapterFile;
|
||||
use Joomla\CMS\Installer\Installer as JInstaller;
|
||||
use Joomla\CMS\Log\Log as JLog;
|
||||
|
||||
if (class_exists('file_fefInstallerScript'))
|
||||
{
|
||||
// WTAF?!
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Akeeba FEF Installation Script
|
||||
*
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class file_fefInstallerScript
|
||||
{
|
||||
/**
|
||||
* The minimum PHP version required to install this extension
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $minimumPHPVersion = '7.2.0';
|
||||
|
||||
/**
|
||||
* The minimum Joomla! version required to install this extension
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $minimumJoomlaVersion = '3.9.0';
|
||||
|
||||
/**
|
||||
* The maximum Joomla! version this extension can be installed on
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $maximumJoomlaVersion = '4.999.999';
|
||||
|
||||
/**
|
||||
* Joomla! pre-flight event. This runs before Joomla! installs or updates the component. This is our last chance to
|
||||
* tell Joomla! if it should abort the installation.
|
||||
*
|
||||
* @param string $type Installation type (install, update, discover_install)
|
||||
* @param JInstaller|JInstallerAdapterFile $parent Parent object
|
||||
*
|
||||
* @return boolean True to let the installation proceed, false to halt the installation
|
||||
*/
|
||||
public function preflight($type, $parent)
|
||||
{
|
||||
// Do not run on uninstall.
|
||||
if ($type === 'uninstall')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the minimum PHP version
|
||||
if (!empty($this->minimumPHPVersion))
|
||||
{
|
||||
if (defined('PHP_VERSION'))
|
||||
{
|
||||
$version = PHP_VERSION;
|
||||
}
|
||||
elseif (function_exists('phpversion'))
|
||||
{
|
||||
$version = phpversion();
|
||||
}
|
||||
else
|
||||
{
|
||||
$version = '5.0.0'; // all bets are off!
|
||||
}
|
||||
|
||||
if (!version_compare($version, $this->minimumPHPVersion, 'ge'))
|
||||
{
|
||||
$msg = "<p>You need PHP $this->minimumPHPVersion or later to install this package but you are currently using PHP $version</p>";
|
||||
|
||||
JLog::add($msg, JLog::WARNING, 'jerror');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the minimum Joomla! version
|
||||
if (!empty($this->minimumJoomlaVersion) && !version_compare(JVERSION, $this->minimumJoomlaVersion, 'ge'))
|
||||
{
|
||||
$jVersion = JVERSION;
|
||||
$msg = "<p>You need Joomla! $this->minimumJoomlaVersion or later to install this package but you only have $jVersion installed.</p>";
|
||||
|
||||
JLog::add($msg, JLog::WARNING, 'jerror');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the maximum Joomla! version
|
||||
if (!empty($this->maximumJoomlaVersion) && !version_compare(JVERSION, $this->maximumJoomlaVersion, 'le'))
|
||||
{
|
||||
$jVersion = JVERSION;
|
||||
$msg = <<< HTML
|
||||
<h3>FEF is no longer needed on Joomla 5</h3>
|
||||
<p>
|
||||
<strong>Summary: FEF is no longer used on Joomla 5. Please uninstall it.</strong>
|
||||
</p>
|
||||
<hr/>
|
||||
<p>
|
||||
Akeeba FEF a.k.a. the Akeeba Front-End Framework was a CSS and JavaScript framework used by Akeeba Ltd with the Joomla 3 versions of our software.
|
||||
</p>
|
||||
<p>
|
||||
Akeeba Ltd has stopped using the FEF framework for developing extensions. All of our extensions have new, Joomla 4 and later native versions which use the Bootstrap library, included in Joomla itself.
|
||||
</p>
|
||||
<p>
|
||||
You can no longer install or update FEF on Joomla 5.0 and later (you have {$jVersion}). In fact, you just need to uninstall it.
|
||||
</p>
|
||||
HTML;
|
||||
|
||||
JLog::add($msg, JLog::WARNING, 'jerror');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// In case of an update, discovery etc I need to check if I am an update
|
||||
if (($type == 'update') && !$this->amIAnUpdate($parent))
|
||||
{
|
||||
$msg = "<p>You already have a newer version of Akeeba Frontend Framework installed. If you want to downgrade please uninstall Akeeba Frontend Framework and install the older version.</p><p>If you see this message during the installation or update of an Akeeba extension please ignore it <em>and</em> the immediately following “Files Install: Custom install routine failure” message. They are expected but Joomla! won't allow us to prevent them from showing up.</p>";
|
||||
|
||||
JLog::add($msg, JLog::WARNING, 'jerror');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete obsolete font files and folders
|
||||
if ($type == 'update')
|
||||
{
|
||||
// Use pathnames relative to your site's root
|
||||
$removeFiles = [
|
||||
'files' => [
|
||||
// Non-WOFF fonts are not shipped as of 1.0.1 since all modern browsers we target use WOFF
|
||||
'media/fef/fonts/akeeba/Akeeba-Products.eot',
|
||||
'media/fef/fonts/akeeba/Akeeba-Products.svg',
|
||||
'media/fef/fonts/akeeba/Akeeba-Products.ttf',
|
||||
'media/fef/fonts/Ionicon/ionicons.eot',
|
||||
'media/fef/fonts/Ionicon/ionicons.svg',
|
||||
'media/fef/fonts/Ionicon/ionicons.ttf',
|
||||
// Files renamed in 1.0.8
|
||||
'css/reset.min.css',
|
||||
'css/style.min.css',
|
||||
// JavaScript: Irrelevant for Joomla
|
||||
'js/darkmode.js',
|
||||
'js/darkmode.min.js',
|
||||
'js/darkmode.map',
|
||||
'js/Darkmode.min.js',
|
||||
'js/Darkmode.map',
|
||||
'js/menu.js',
|
||||
'js/menu.min.js',
|
||||
'js/menu.map',
|
||||
'js/Menu.min.js',
|
||||
'js/Menu.map',
|
||||
// JavaScript: Uncompressed and map files
|
||||
'js/dropdown.js',
|
||||
'js/dropdown.map',
|
||||
'js/Dropdown.map',
|
||||
'js/loader.js',
|
||||
'js/loader.map',
|
||||
'js/Loader.map',
|
||||
'js/tabs.js',
|
||||
'js/tabs.map',
|
||||
'js/Tabs.map',
|
||||
],
|
||||
'folders' => [
|
||||
],
|
||||
];
|
||||
|
||||
// Remove obsolete files and folders
|
||||
$this->removeFilesAndFolders($removeFiles);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs after install, update or discover_update. In other words, it executes after Joomla! has finished installing
|
||||
* or updating your component. This is the last chance you've got to perform any additional installations, clean-up,
|
||||
* database updates and similar housekeeping functions.
|
||||
*
|
||||
* @param string $type install, update or discover_update
|
||||
* @param JInstallerAdapterFile $parent Parent object
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function postflight($type, JInstallerAdapterFile $parent)
|
||||
{
|
||||
// Do not run on uninstall.
|
||||
if ($type === 'uninstall')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Auto-uninstall this package when it is no longer needed.
|
||||
if (($type != 'install') && ($this->countHardcodedDependencies() === 0))
|
||||
{
|
||||
$this->uninstallSelf($parent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->bugfixFilesNotCopiedOnUpdate($parent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on uninstallation
|
||||
*
|
||||
* @param JInstallerAdapterFile $parent The parent object
|
||||
*
|
||||
* @throws RuntimeException If the uninstallation is not allowed
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function uninstall($parent)
|
||||
{
|
||||
if (version_compare(JVERSION, '4.1.0', 'ge'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check dependencies on FEF
|
||||
$dependencyCount = $this->countHardcodedDependencies();
|
||||
|
||||
if ($dependencyCount)
|
||||
{
|
||||
$msg = "<p>You have $dependencyCount extension(s) depending on Akeeba Frontend Framework. The package cannot be uninstalled unless these extensions are uninstalled first.</p>";
|
||||
|
||||
JLog::add($msg, JLog::WARNING, 'jerror');
|
||||
|
||||
throw new RuntimeException($msg, 500);
|
||||
}
|
||||
|
||||
Folder::delete(JPATH_SITE . '/media/fef');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes obsolete files and folders
|
||||
*
|
||||
* @param array $removeList The files and directories to remove
|
||||
*/
|
||||
protected function removeFilesAndFolders($removeList)
|
||||
{
|
||||
// Remove files
|
||||
if (isset($removeList['files']) && !empty($removeList['files']))
|
||||
{
|
||||
foreach ($removeList['files'] as $file)
|
||||
{
|
||||
$f = JPATH_ROOT . '/' . $file;
|
||||
|
||||
if (!is_file($f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
File::delete($f);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove folders
|
||||
if (isset($removeList['folders']) && !empty($removeList['folders']))
|
||||
{
|
||||
foreach ($removeList['folders'] as $folder)
|
||||
{
|
||||
$f = JPATH_ROOT . '/' . $folder;
|
||||
|
||||
if (!is_dir($f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Folder::delete($f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this package an update to the currently installed FEF? If not (we're a downgrade) we will return false
|
||||
* and prevent the installation from going on.
|
||||
*
|
||||
* @param JInstallerAdapterFile $parent The parent object
|
||||
*
|
||||
* @return bool Am I an update to an existing version>
|
||||
*/
|
||||
protected function amIAnUpdate($parent)
|
||||
{
|
||||
$grandpa = $parent->getParent();
|
||||
$source = $grandpa->getPath('source');
|
||||
$target = JPATH_ROOT . '/media/fef';
|
||||
|
||||
if (!Folder::exists($source))
|
||||
{
|
||||
// WTF? I can't find myself. I can't install anything.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If FEF is not really installed (someone removed the directory instead of uninstalling?) I have to install it.
|
||||
if (!Folder::exists($target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$fefVersion = [];
|
||||
|
||||
if (File::exists($target . '/version.txt'))
|
||||
{
|
||||
$rawData = @file_get_contents($target . '/version.txt');
|
||||
$rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
|
||||
$info = explode("\n", $rawData);
|
||||
$fefVersion['installed'] = [
|
||||
'version' => trim($info[0]),
|
||||
'date' => new JDate(trim($info[1])),
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$fefVersion['installed'] = [
|
||||
'version' => '0.0',
|
||||
'date' => new JDate('2011-01-01'),
|
||||
];
|
||||
}
|
||||
|
||||
$rawData = @file_get_contents($source . '/version.txt');
|
||||
$rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
|
||||
$info = explode("\n", $rawData);
|
||||
$fefVersion['package'] = [
|
||||
'version' => trim($info[0]),
|
||||
'date' => new JDate(trim($info[1])),
|
||||
];
|
||||
|
||||
return $fefVersion['package']['date']->toUNIX() >= $fefVersion['installed']['date']->toUNIX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix for Joomla bug: sometimes files are not copied on update.
|
||||
*
|
||||
* We have observed that ever since Joomla! 1.5.5, when Joomla! is performing an extension update some files /
|
||||
* folders are not copied properly. This seems to be a bit random and seems to be more likely to happen the more
|
||||
* added / modified files and folders you have. We are trying to work around it by retrying the copy operation
|
||||
* ourselves WITHOUT going through the manifest, based entirely on the conventions we follow.
|
||||
*
|
||||
* @param \Joomla\CMS\Installer\Adapter\FileAdapter $parent
|
||||
*/
|
||||
protected function bugfixFilesNotCopiedOnUpdate($parent)
|
||||
{
|
||||
$source = $parent->getParent()->getPath('source');
|
||||
$target = JPATH_SITE . '/media/fef';
|
||||
|
||||
$this->recursiveConditionalCopy($source, $target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively copy a bunch of files, but only if the source and target file have a different size.
|
||||
*
|
||||
* @param string $source Path to copy FROM
|
||||
* @param string $dest Path to copy TO
|
||||
* @param array $ignored List of entries to ignore (first level entries are taken into account)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function recursiveConditionalCopy($source, $dest, $ignored = [])
|
||||
{
|
||||
// Make sure source and destination exist
|
||||
if (!@is_dir($source))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!@is_dir($dest))
|
||||
{
|
||||
if (!@mkdir($dest, 0755))
|
||||
{
|
||||
Folder::create($dest, 0755);
|
||||
}
|
||||
}
|
||||
|
||||
if (!@is_dir($dest))
|
||||
{
|
||||
// Cannot create folder $dest
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// List the contents of the source folder
|
||||
try
|
||||
{
|
||||
$di = new DirectoryIterator($source);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Process each entry
|
||||
foreach ($di as $entry)
|
||||
{
|
||||
// Ignore dot dirs (. and ..)
|
||||
if ($entry->isDot())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourcePath = $entry->getPathname();
|
||||
$fileName = $entry->getFilename();
|
||||
|
||||
// Do not copy ignored files
|
||||
if (!empty($ignored) && in_array($fileName, $ignored))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's a directory do a recursive copy
|
||||
if ($entry->isDir())
|
||||
{
|
||||
$this->recursiveConditionalCopy($sourcePath, $dest . DIRECTORY_SEPARATOR . $fileName);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's a file check if it's missing or identical
|
||||
$mustCopy = false;
|
||||
$targetPath = $dest . DIRECTORY_SEPARATOR . $fileName;
|
||||
|
||||
if (!@is_file($targetPath))
|
||||
{
|
||||
$mustCopy = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sourceSize = @filesize($sourcePath);
|
||||
$targetSize = @filesize($targetPath);
|
||||
|
||||
$mustCopy = $sourceSize != $targetSize;
|
||||
|
||||
if ((substr($targetPath, -4) === '.php') && function_exists('opcache_invalidate'))
|
||||
{
|
||||
opcache_invalidate($targetPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$mustCopy)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!@copy($sourcePath, $targetPath))
|
||||
{
|
||||
File::copy($sourcePath, $targetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of old FOF + FEF based extensions installed on this site
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function countHardcodedDependencies()
|
||||
{
|
||||
// Look for fof.xml in the backend directories of the following components
|
||||
$hardcodedDependencies = [
|
||||
'com_admintools',
|
||||
'com_akeeba',
|
||||
'com_ars',
|
||||
'com_ats',
|
||||
'com_compatibility',
|
||||
'com_datacompliance',
|
||||
'com_contactus',
|
||||
'com_docimport',
|
||||
'com_loginguard',
|
||||
];
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($hardcodedDependencies as $component)
|
||||
{
|
||||
$filePath = JPATH_ADMINISTRATOR . '/components/' . $component . '/fof.xml';
|
||||
|
||||
if (@file_exists($filePath))
|
||||
{
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall this package.
|
||||
*
|
||||
* This runs on update when there are no more dependencies left.
|
||||
*
|
||||
* @param \Joomla\CMS\Installer\Adapter\FileAdapter $adapter
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function uninstallSelf($adapter)
|
||||
{
|
||||
$parent = $adapter->getParent();
|
||||
|
||||
if (empty($parent) || !property_exists($parent, 'extension'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (version_compare(JVERSION, '4.0', 'lt'))
|
||||
{
|
||||
$db = \Joomla\CMS\Factory::getDbo();
|
||||
}
|
||||
else
|
||||
{
|
||||
$db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName('extension_id'))
|
||||
->from($db->quoteName('#__extensions'))
|
||||
->where($db->quoteName('type') . ' = ' . $db->quote('file'))
|
||||
->where($db->quoteName('name') . ' = ' . $db->quote('file_fef'));
|
||||
|
||||
$id = $db->setQuery($query)->loadResult();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$msg = 'Automatically uninstalling FEF; this package is no longer required on your site.';
|
||||
\Joomla\CMS\Log\Log::add($msg, \Joomla\CMS\Log\Log::INFO, 'jerror');
|
||||
|
||||
$parent->uninstall('file', $id);
|
||||
}
|
||||
}
|
||||
14
media/fef/version.php
Normal file
14
media/fef/version.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Akeeba Frontend Framework (FEF)
|
||||
*
|
||||
* @package fef
|
||||
* @copyright (c) 2017-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
// Protect from unauthorized access
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
define('AKEEBAFEF_VERSION', '2.1.1');
|
||||
define('AKEEBAFEF_DATE', '2022-10-24');
|
||||
2
media/fef/version.txt
Normal file
2
media/fef/version.txt
Normal file
@ -0,0 +1,2 @@
|
||||
2.1.1
|
||||
2022-10-24
|
||||
Reference in New Issue
Block a user