diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 0000000..2ee6c59
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,10 @@
+{
+ "permissions": {
+ "allow": [
+ "mcp__serena__activate_project",
+ "mcp__serena__list_dir",
+ "mcp__serena__read_file",
+ "mcp__serena__find_file"
+ ]
+ }
+}
diff --git a/.serena/.gitignore b/.serena/.gitignore
new file mode 100644
index 0000000..14d86ad
--- /dev/null
+++ b/.serena/.gitignore
@@ -0,0 +1 @@
+/cache
diff --git a/.serena/project.yml b/.serena/project.yml
new file mode 100644
index 0000000..e83de81
--- /dev/null
+++ b/.serena/project.yml
@@ -0,0 +1,126 @@
+# the name by which the project can be referenced within Serena
+project_name: "newwalls.pl"
+
+
+# list of languages for which language servers are started; choose from:
+# al bash clojure cpp csharp
+# csharp_omnisharp dart elixir elm erlang
+# fortran fsharp go groovy haskell
+# java julia kotlin lua markdown
+# matlab nix pascal perl php
+# php_phpactor powershell python python_jedi r
+# rego ruby ruby_solargraph rust scala
+# swift terraform toml typescript typescript_vts
+# vue yaml zig
+# (This list may be outdated. For the current list, see values of Language enum here:
+# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
+# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
+# Note:
+# - For C, use cpp
+# - For JavaScript, use typescript
+# - For Free Pascal/Lazarus, use pascal
+# Special requirements:
+# Some languages require additional setup/installations.
+# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
+# When using multiple languages, the first language server that supports a given file will be used for that file.
+# The first language is the default language and the respective language server will be used as a fallback.
+# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
+languages:
+- php
+
+# the encoding used by text files in the project
+# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
+encoding: "utf-8"
+
+# The language backend to use for this project.
+# If not set, the global setting from serena_config.yml is used.
+# Valid values: LSP, JetBrains
+# Note: the backend is fixed at startup. If a project with a different backend
+# is activated post-init, an error will be returned.
+language_backend:
+
+# whether to use project's .gitignore files to ignore files
+ignore_all_files_in_gitignore: true
+
+# list of additional paths to ignore in this project.
+# Same syntax as gitignore, so you can use * and **.
+# Note: global ignored_paths from serena_config.yml are also applied additively.
+ignored_paths: []
+
+# whether the project is in read-only mode
+# If set to true, all editing tools will be disabled and attempts to use them will result in an error
+# Added on 2025-04-18
+read_only: false
+
+# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
+# Below is the complete list of tools for convenience.
+# To make sure you have the latest list of tools, and to view their descriptions,
+# execute `uv run scripts/print_tool_overview.py`.
+#
+# * `activate_project`: Activates a project by name.
+# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
+# * `create_text_file`: Creates/overwrites a file in the project directory.
+# * `delete_lines`: Deletes a range of lines within a file.
+# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
+# * `execute_shell_command`: Executes a shell command.
+# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
+# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
+# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
+# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
+# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
+# * `initial_instructions`: Gets the initial instructions for the current project.
+# Should only be used in settings where the system prompt cannot be set,
+# e.g. in clients you have no control over, like Claude Desktop.
+# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
+# * `insert_at_line`: Inserts content at a given line in a file.
+# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
+# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
+# * `list_memories`: Lists memories in Serena's project-specific memory store.
+# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
+# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
+# * `read_file`: Reads a file within the project directory.
+# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
+# * `remove_project`: Removes a project from the Serena configuration.
+# * `replace_lines`: Replaces a range of lines within a file with new content.
+# * `replace_symbol_body`: Replaces the full definition of a symbol.
+# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
+# * `search_for_pattern`: Performs a search for a pattern in the project.
+# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
+# * `switch_modes`: Activates modes by providing a list of their names
+# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
+# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
+# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
+# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
+excluded_tools: []
+
+# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default)
+included_optional_tools: []
+
+# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
+# This cannot be combined with non-empty excluded_tools or included_optional_tools.
+fixed_tools: []
+
+# list of mode names to that are always to be included in the set of active modes
+# The full set of modes to be activated is base_modes + default_modes.
+# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
+# Otherwise, this setting overrides the global configuration.
+# Set this to [] to disable base modes for this project.
+# Set this to a list of mode names to always include the respective modes for this project.
+base_modes:
+
+# list of mode names that are to be activated by default.
+# The full set of modes to be activated is base_modes + default_modes.
+# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
+# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
+# This setting can, in turn, be overridden by CLI parameters (--mode).
+default_modes:
+
+# initial prompt for the project. It will always be given to the LLM upon activating the project
+# (contrary to the memories, which are loaded on demand).
+initial_prompt: ""
+
+# time budget (seconds) per tool call for the retrieval of additional symbol information
+# such as docstrings or parameter information.
+# This overrides the corresponding setting in the global configuration; see the documentation there.
+# If null or missing, use the setting from the global configuration.
+symbol_info_budget:
diff --git a/.vscode/ftp-kr.json b/.vscode/ftp-kr.json
index 9bf4188..3b847ea 100644
--- a/.vscode/ftp-kr.json
+++ b/.vscode/ftp-kr.json
@@ -12,6 +12,8 @@
"ignoreRemoteModification": true,
"ignore": [
".git",
- "/.vscode"
+ "/.vscode",
+ "/.claude",
+ "/.serena"
]
}
\ No newline at end of file
diff --git a/config/defines.inc.php b/config/defines.inc.php
index 6ba618f..241ce16 100644
--- a/config/defines.inc.php
+++ b/config/defines.inc.php
@@ -26,7 +26,10 @@
/* Debug only */
if (!defined('_PS_MODE_DEV_')) {
-define('_PS_MODE_DEV_', false);
+ if ( $_SERVER['REMOTE_ADDR'] == '91.189.216.43' )
+ define('_PS_MODE_DEV_', false);
+ else
+ define('_PS_MODE_DEV_', false);
}
/* Compatibility warning */
define('_PS_DISPLAY_COMPATIBILITY_WARNING_', false);
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..b08bc1b
--- /dev/null
+++ b/index.php
@@ -0,0 +1,28 @@
+
+ * @copyright Since 2007 PrestaShop SA and Contributors
+ * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ */
+
+require dirname(__FILE__).'/config/config.inc.php';
+Dispatcher::getInstance()->dispatch();
diff --git a/modules/cookiesplus/cookiesplus.php b/modules/cookiesplus/cookiesplus.php
new file mode 100644
index 0000000..e9e2d89
--- /dev/null
+++ b/modules/cookiesplus/cookiesplus.php
@@ -0,0 +1,2447 @@
+name = 'cookiesplus';
+ $this->tab = 'front_office_features';
+ $this->version = '1.6.0';
+ $this->author = 'idnovate';
+ $this->need_instance = 0;
+ $this->module_key = '22c3b977fe9c819543a216a2fd948f22';
+ // $this->author_address = '0xd89bcCAeb29b2E6342a74Bc0e9C82718Ac702160';
+ $this->bootstrap = true;
+ $this->addons_id_product = '21644';
+ $this->ps_versions_compliancy = ['min' => '1.5', 'max' => _PS_VERSION_];
+
+ parent::__construct();
+
+ $this->displayName = $this->l('Cookies - GDPR Cookie law (block before consent)');
+ $this->description = $this->l('Make your store GDPR compliant using this module. This module lets you block the cookies until the customer gives his consent accepting the notice.');
+ $this->confirmUninstall = $this->l('Are you sure you want to delete the module and the related data?');
+
+ $this->tabs = [
+ [
+ 'class_name' => 'COOKIES',
+ 'parent_class_name' => 'CONFIGURE',
+ 'name' => [
+ 'en' => 'Cookies configuration',
+ 'es' => 'Configuración de cookies',
+ 'de' => 'Konfiguration von Cookies',
+ 'fr' => 'Configuration des cookies',
+ 'it' => 'Configurazione dei cookie',
+ 'nl' => 'Cookies configuratie',
+ 'pl' => 'Konfiguracja plików cookie',
+ 'pt' => 'Configuração de cookies',
+ 'ro' => 'Configurarea modulelor cookie',
+ 'ru' => 'Конфигурация файлов cookie',
+ 'se' => 'Cookies konfiguration',
+ ],
+ 'module' => $this->name,
+ 'icon' => 'group_work',
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusConfiguration',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Configuration',
+ 'es' => 'Configuración',
+ 'de' => 'Aufbau',
+ 'fr' => 'Configuration',
+ 'it' => 'Configurazione',
+ 'nl' => 'Configuratie',
+ 'pl' => 'Konfiguracja',
+ 'pt' => 'Configuração',
+ 'ro' => 'Configurație',
+ 'ru' => 'Конфигурация',
+ 'se' => 'Konfiguration',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusAppearance',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Appearance',
+ 'es' => 'Apariencia',
+ 'de' => 'Aussehen',
+ 'fr' => 'Apparence',
+ 'it' => 'Aspetto',
+ 'nl' => 'Uiterlijk',
+ 'pl' => 'Wygląd',
+ 'pt' => 'Aparência',
+ 'ro' => 'Aspect',
+ 'ru' => 'вид',
+ 'se' => 'Utseende',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusFinalities',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Cookie finalities',
+ 'es' => 'Finalidades de cookie',
+ 'de' => 'Cookie-Endgültigkeiten',
+ 'fr' => 'Finalités des cookies',
+ 'it' => 'Finalità dei cookie',
+ 'nl' => 'Cookie finaliteiten',
+ 'pl' => 'Ostateczna wersja plików cookie',
+ 'pt' => 'Finalidades do cookie',
+ 'ro' => 'Finalitățile cookie-urilor',
+ 'ru' => 'Окончательность файлов cookie',
+ 'se' => 'Cookie finaliteter',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusCookies',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Cookies',
+ 'es' => 'Cookies',
+ 'de' => 'Cookies',
+ 'fr' => 'Cookies',
+ 'it' => 'Cookies',
+ 'nl' => 'Cookies',
+ 'pl' => 'Cookies',
+ 'pt' => 'Cookies',
+ 'ro' => 'Cookies',
+ 'ru' => 'Cookies',
+ 'se' => 'Cookies',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusGTM',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Google Tag Manager (GTM)',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusFB',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Facebook Pixel',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusYT',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'YouTube',
+ ],
+ 'module' => $this->name,
+ ],
+ [
+ 'class_name' => 'AdminCookiesPlusUsersConsent',
+ 'parent_class_name' => 'COOKIES',
+ 'name' => [
+ 'en' => 'Users consent',
+ 'es' => 'Consentimiento de los usuarios',
+ 'de' => 'Zustimmung der Benutzer',
+ 'fr' => 'Consentement des utilisateurs',
+ 'it' => 'Consenso degli utenti',
+ 'nl' => 'Gebruikers toestemming',
+ 'pl' => 'Zgoda użytkowników',
+ 'pt' => 'Consentimento dos usuários',
+ 'ro' => 'Utilizatorii sunt de acord',
+ 'ru' => 'Согласие пользователей',
+ 'se' => 'Användarens samtycke',
+ ],
+ 'module' => $this->name,
+ ],
+ ];
+ }
+
+ public function install()
+ {
+ $result = include dirname(__FILE__) . '/sql/install.php';
+ if (!$result) {
+ $this->_errors[] = $this->l('Error creating tables');
+ return false;
+ }
+
+ $result = $this->copyOverrideFolder();
+ if (!$result) {
+ $this->_errors[] = $this->l('Error copying overrides');
+ return false;
+ }
+
+ $result = parent::install();
+ if (!$result) {
+ $this->_errors[] = $this->l('Error in parent::install');
+ return false;
+ }
+
+ // Hooks
+ $result = true;
+ $result &= $this->registerHook('displayHeader');
+
+ // If there's only 1 position it returns false, so we discard the $result
+ $this->updatePosition(Hook::getIdByName('displayHeader'), 0, 1);
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ $result &= $this->registerHook('top');
+ }
+
+ if (version_compare(_PS_VERSION_, '1.7', '>=')) {
+ $result &= $this->registerHook('displayBeforeBodyClosingTag');
+ }
+
+ if (Module::isInstalled('mobile_theme')) {
+ $result &= $this->registerHook('displayMobileHeader');
+ }
+ $result &= $this->registerHook('displayMyAccountBlock');
+ $result &= $this->registerHook('displayMyAccountBlockfooter');
+ $result &= $this->registerHook('tmMegaLayoutFooter');
+ $result &= $this->registerHook('displayCookies');
+ $result &= $this->registerHook('displayCookiesHeader');
+ $result &= $this->registerHook('customerAccount');
+ $result &= $this->registerHook('displayBackOfficeHeader');
+ $result &= $this->registerHook('displayAfterBodyOpeningTag');
+ $result &= $this->registerHook('actionShopDataDuplication');
+ $result &= $this->registerHook('actionOutputHTMLBefore');
+ $result &= $this->registerHook('actionHtaccessCreate');
+
+ if (Module::isInstalled('cdc_googletagmanager')) {
+ $cdc_googletagmanager = Module::getInstanceByName('cdc_googletagmanager');
+ // if (version_compare($cdc_googletagmanager->version, '5', '')) {
+ $result &= $this->registerHook('displayAfterTitle');
+ $this->updatePosition(Hook::getIdByName('displayAfterTitle'), 0, 1);
+ // } else {
+ $result &= $this->registerHook('displayAfterTitleTag');
+ $this->updatePosition(Hook::getIdByName('displayAfterTitleTag'), 0, 1);
+ // }
+ }
+
+ // GDPR module
+ $result &= $this->registerHook('registerGDPRConsent');
+
+ if (!$result) {
+ $this->_errors[] = $this->l('Error registering hooks');
+ return false;
+ }
+
+ // Tabs
+ $result = $this->installTabs($this->tabs);
+ if (!$result) {
+ $this->_errors[] = $this->l('Error installing tabs');
+ return false;
+ }
+
+ $result = $this->setDefaultValues();
+ if (!$result) {
+ $this->_errors[] = $this->l('Error setting default values');
+ return false;
+ }
+
+ // Cache modules
+ /*if (Module::isInstalled('litespeedcache')) {
+ $litespeedcacheConfig = json_decode(Configuration::get('LITESPEED_CACHE_MODULE'), true);
+
+ if (!isset($litespeedcacheConfig['cookiesplus'])) {
+ $litespeedcacheConfig['cookiesplus'] = array(
+ 'module' => 'cookiesplus',
+ 'name' => '',
+ 'priv' => 1,
+ 'ttl' => 1800,
+ 'tag' => 'cookiesplus',
+ 'events' => '',
+ 'ctrl' => '',
+ 'methods' => '!hookDisplayHeader',
+ 'render' => '*',
+ 'asvar' => 1,
+ 'ie' => 0,
+ 'ce' => 1,
+ );
+
+ Configuration::updateValue('LITESPEED_CACHE_MODULE', json_encode($litespeedcacheConfig));
+ }
+ }
+
+ if (Module::isInstalled('stadvancedcache')) {
+ $stadvancedcacheConfig = unserialize(Configuration::get('ST_ADVCACHE_DYN_HOOKS'));
+
+ if (!isset($stadvancedcacheConfig['cookiesplus'])) {
+ $stadvancedcacheConfig['cookiesplus'] = array(
+ 'header',
+ 'displayBeforeBodyClosingTag'
+ );
+
+ Configuration::updateValue('ST_ADVCACHE_DYN_HOOKS', serialize($stadvancedcacheConfig));
+
+ $stadvancedcache = new StAdvancedCache();
+ $stadvancedcache->clearAllCache();
+ }
+ }
+
+ if (Module::isInstalled('jprestaspeedpack')) {
+ $jprestaspeedpackConfig = Configuration::get('pagecache_dyn_hooks');
+
+ if (strpos($jprestaspeedpackConfig, 'cookiesplus') === false) {
+ $jprestaspeedpackConfig .= 'displaybeforebodyclosingtag|cookiesplus|0,';
+
+ Configuration::updateValue('pagecache_dyn_hooks', $jprestaspeedpackConfig);
+
+ $jprestaspeedpack = new Jprestaspeedpack();
+ $jprestaspeedpack->clearCache();
+ }
+ }*/
+ $result = self::clearCache();
+ if (!$result) {
+ $this->_errors[] = $this->l('Error clearing cache');
+ return false;
+ }
+
+ $result = Tools::generateHtaccess();
+ if (!$result) {
+ $this->_errors[] = $this->l('Error generating htaccess');
+ return false;
+ }
+
+ return true;
+ }
+
+ public function installTabs($moduleTabs = null)
+ {
+ if (!$moduleTabs) {
+ $moduleTabs = $this->tabs;
+ }
+
+ $languages = Language::getLanguages(false);
+
+ foreach ($moduleTabs as $moduleTab) {
+ if (!Tab::getIdFromClassName($moduleTab['class_name'])) {
+ $tab = new Tab();
+ $tab->class_name = $moduleTab['class_name'];
+ $tab->module = $moduleTab['module'];
+ $tab->active = 1;
+
+ foreach ($languages as $language) {
+ if (is_array($moduleTab['name'])) {
+ if (isset($moduleTab['name'][$language['iso_code']]) && $moduleTab['name'][$language['iso_code']]) {
+ $tab->name[$language['id_lang']] = $moduleTab['name'][$language['iso_code']];
+ } else {
+ $tab->name[$language['id_lang']] = $moduleTab['name']['en'];
+ }
+ } else {
+ $tab->name[$language['id_lang']] = $moduleTab['name'];
+ }
+ }
+
+ if (isset($moduleTab['parent_class_name']) && is_string($moduleTab['parent_class_name'])) {
+ $tab->id_parent = Tab::getIdFromClassName($moduleTab['parent_class_name']);
+ } elseif (isset($moduleTab['id_parent'])) {
+ $tab->id_parent = $moduleTab['id_parent'];
+ } else {
+ $tab->id_parent = -1;
+ }
+
+ if (isset($moduleTab['icon'])) {
+ $tab->icon = $moduleTab['icon'];
+ }
+
+ $tab->add();
+ if (!$tab->id) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static function clearCache()
+ {
+ if (method_exists('Tools', 'clearAllCache')) {
+ Tools::clearAllCache();
+ }
+
+ if (method_exists('Tools', 'clearSmartyCache')) {
+ Tools::clearSmartyCache();
+ }
+
+ if (method_exists('Tools', 'clearSf2Cache')) {
+ Tools::clearSf2Cache();
+ }
+
+ if (method_exists('Tools', 'clearCache')) {
+ Tools::clearCache(Context::getContext()->smarty);
+ }
+
+ if (method_exists('Media', 'clearCache')) {
+ Media::clearCache();
+ }
+
+ $version = (int) Configuration::get('PS_CCCJS_VERSION');
+ if ($version) {
+ Configuration::updateValue('PS_CCCJS_VERSION', ++$version);
+ }
+
+ $version = (int) Configuration::get('PS_CCCCSS_VERSION');
+ if ($version) {
+ Configuration::updateValue('PS_CCCCSS_VERSION', ++$version);
+ }
+
+ return true;
+ }
+
+ public function uninstall()
+ {
+ $result = true;
+
+ $result &= $this->copyOverrideFolder();
+
+ $result &= parent::uninstall();
+
+ $result &= $this->uninstallTabs();
+
+ include dirname(__FILE__) . '/sql/uninstall.php';
+
+ /*if (Module::isInstalled('litespeedcache')) {
+ $litespeedcacheConfig = json_decode(Configuration::get('LITESPEED_CACHE_MODULE'), true);
+
+ if (isset($litespeedcacheConfig['cookiesplus'])) {
+ unset($litespeedcacheConfig['cookiesplus']);
+
+ Configuration::updateValue('LITESPEED_CACHE_MODULE', json_encode($litespeedcacheConfig));
+ }
+
+ if (Module::isInstalled('stadvancedcache')) {
+ $stadvancedcacheConfig = unserialize(Configuration::get('ST_ADVCACHE_DYN_HOOKS'));
+
+ if (isset($stadvancedcacheConfig['cookiesplus'])) {
+ unset($stadvancedcacheConfig['cookiesplus']);
+
+ Configuration::updateValue('ST_ADVCACHE_DYN_HOOKS', serialize($stadvancedcacheConfig));
+
+ $stadvancedcache = new StAdvancedCache();
+ $stadvancedcache->clearAllCache();
+ }
+ }
+ }*/
+ $result &= self::clearCache();
+
+ $result &= Tools::generateHtaccess();
+
+ return (bool) $result;
+ }
+
+ public function uninstallTabs($moduleTabs = null)
+ {
+ if (!$moduleTabs) {
+ $moduleTabs = Tab::getCollectionFromModule($this->name);
+ foreach ($moduleTabs as $moduleTab) {
+ $moduleTab->delete();
+ }
+ } else {
+ foreach ($moduleTabs as $moduleTab) {
+ $idTab = Tab::getIdFromClassName($moduleTab['class_name']);
+
+ if ($idTab) {
+ $tab = new Tab($idTab);
+ $tab->delete();
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public function enable($force_all = false)
+ {
+ if (!$this->copyOverrideFolder()) {
+ return false;
+ }
+
+ $result = true;
+
+ $result &= parent::enable($force_all);
+
+ $result &= Tools::generateHtaccess();
+
+ return (bool) $result;
+ }
+
+ public function disable($force_all = false)
+ {
+ if (!$this->copyOverrideFolder()) {
+ return false;
+ }
+
+ $result = true;
+
+ $result &= parent::disable($force_all);
+
+ $result &= Tools::generateHtaccess();
+ // Bypass if (!defined('PS_INSTALLATION_IN_PROGRESS')) {
+ $this->hookActionHtaccessCreate();
+
+ return (bool) $result;
+ }
+
+ public function setDefaultValues()
+ {
+ Configuration::updateValue('C_P_REVOKE_CONSENT', date('Y-m-d H:i:s', time()));
+
+ Configuration::updateValue('C_P_REFRESH', 0);
+ Configuration::updateValue('C_P_EXPIRY', '365');
+ Configuration::updateValue('C_P_BOTS', 'Ahrefs|ADmantX|Alexa|AskJeeves|Baidu|Bing|Butterfly|Cookiebot|crawler|DuckDuckGo|exabot|Evaliant|Facebook|Firefly|Froogle|Gigabot|Google|Googlebot|Grapeshot|Inktomi|InfoSeek|Lighthouse|Looksmart|MeanPath|Mediapartners-Google|Me.dium|MJ12bot|MSN|NationalDirectory|OpenSiteExplorer|Pinterest|Proximic|Rankivabot|Scooter|Sogou|Sogouwebspider|Sosospider|Squider|TechnoratiSnoop|TECNOSEEK|Teoma|TweetmemeBot|TweetMeme|Twiceler|Twitturls|URL_Spider_SQL|WebAltaCrawler|WebFindBot|www.galaxy.com|Yaho|Yandex|Ahrefs|YodaoBot');
+ Configuration::updateValue('C_P_HOOK_POSITION', 0);
+ Configuration::updateValue('C_P_OVERLAY_OPACITY', '0.5');
+ Configuration::updateValue('C_P_GEO', '0');
+ Configuration::updateValue('C_P_POSITION', 'center');
+ Configuration::updateValue('C_P_WIDTH', '50');
+ Configuration::updateValue('C_P_ACCEPT_DISPLAY', 1);
+ Configuration::updateValue('C_P_MORE_INFO_DISPLAY', 1);
+ Configuration::updateValue('C_P_OVERLAY', 1);
+ Configuration::updateValue('C_P_OVERLAY_OPACITY', '0.5');
+ Configuration::updateValue('C_P_BUTTON_POSITION', '1');
+
+ Configuration::updateValue('C_P_FONT_COLOR', '#000');
+ Configuration::updateValue('C_P_BACKGROUND_COLOR', '#FFFFFF');
+
+ Configuration::updateValue('C_P_ACCEPT_FONT_SIZE', '16px');
+ Configuration::updateValue('C_P_ACCEPT_BACKGROUND_COLOR', '#20BF6B');
+ Configuration::updateValue('C_P_ACCEPT_BORDER_COLOR', '#20BF6B');
+ Configuration::updateValue('C_P_ACCEPT_FONT_COLOR', '#FFFFFF');
+
+ Configuration::updateValue('C_P_MORE_INFO_FONT_SIZE', '16px');
+ Configuration::updateValue('C_P_MORE_INFO_BACKGROUND_COLOR', '#FFFFFF');
+ Configuration::updateValue('C_P_MORE_INFO_BORDER_COLOR', '#7A7A7A');
+ Configuration::updateValue('C_P_MORE_INFO_FONT_COLOR', '#000');
+
+ Configuration::updateValue('C_P_REJECT_FONT_SIZE', '16px');
+ Configuration::updateValue('C_P_REJECT_BACKGROUND_COLOR', '#FFFFFF');
+ Configuration::updateValue('C_P_REJECT_BORDER_COLOR', '#7A7A7A');
+ Configuration::updateValue('C_P_REJECT_FONT_COLOR', '#000');
+
+ Configuration::updateValue('C_P_SAVE_FONT_SIZE', '16px');
+ Configuration::updateValue('C_P_SAVE_BACKGROUND_COLOR', '#FFFFFF');
+ Configuration::updateValue('C_P_SAVE_BORDER_COLOR', '#7A7A7A');
+ Configuration::updateValue('C_P_SAVE_FONT_COLOR', '#000');
+
+ Configuration::updateValue('C_P_REJECT_DISPLAY', '1');
+ Configuration::updateValue('C_P_DEFAULT_CONSENT', true);
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ Configuration::updateValue('C_P_MATERIAL_ICONS_LIBRARY', '1');
+ Configuration::updateValue('C_P_MATERIAL_ICONS', 1);
+ } else {
+ if ($this->context->shop->theme->getName() === 'panda') {
+ Configuration::updateValue('C_P_MATERIAL_ICONS_LIBRARY', 2);
+ } else {
+ Configuration::updateValue('C_P_MATERIAL_ICONS_LIBRARY', 1);
+ }
+ }
+
+ $cookiesDefault = [];
+ // English
+ $langCode = 'en';
+ $cookiesDefault['title'][$langCode] = 'Your cookie settings';
+ $cookiesDefault['text'][$langCode] = '
This store asks you to accept cookies for performance, social media and advertising purposes. Social media and advertising cookies of third parties are used to offer you social media functionalities and personalized ads. Do you accept these cookies and the processing of personal data involved?
Esta tienda te pide que aceptes cookies para fines de rendimiento, redes sociales y publicidad. Las redes sociales y las cookies publicitarias de terceros se utilizan para ofrecerte funciones de redes sociales y anuncios personalizados. ¿Aceptas estas cookies y el procesamiento de datos personales involucrados?
';
+
+ // French
+ $langCode = 'fr';
+ $cookiesDefault['title'][$langCode] = 'Vos paramètres de cookies';
+ $cookiesDefault['text'][$langCode] = '
Ce magasin vous demande d\'accepter les cookies afin d\'optimiser les performances, les fonctionnalités des réseaux sociaux et la pertinence de la publicité. Les cookies tiers liés aux réseaux sociaux et à la publicité sont utilisés pour vous offrir des fonctionnalités optimisées sur les réseaux sociaux, ainsi que des publicités personnalisées. Acceptez-vous ces cookies ainsi que les implications associées à l\'utilisation de vos données personnelles ?
Ce magasin vous demande d\'accepter les cookies afin d\'optimiser les performances, les fonctionnalités des réseaux sociaux et la pertinence de la publicité. Les cookies tiers liés aux réseaux sociaux et à la publicité sont utilisés pour vous offrir des fonctionnalités optimisées sur les réseaux sociaux, ainsi que des publicités personnalisées. Acceptez-vous ces cookies ainsi que les implications associées à l\'utilisation de vos données personnelles ?
Niniejsza witryna wykorzystuje pliki cookies w celu świadczenia usług na najwyższym poziomie i w sposób dostosowany do indywidualnych potrzeb. Korzystanie z witryny bez zmiany ustawień dotyczących cookies oznacza, że będą one zamieszczane w urządzeniu końcowym. Jeśli nie akceptujesz opuść tę stronę internetową.
Acest magazin vă solicită să acceptați cookie-uri pentru performanță, media și publicitate. Mediile sociale și cookie-urile de publicitate ale unor terțe părți sunt utilizate pentru a vă oferi funcții de social media și anunțuri personalizate. Acceptați aceste cookie-uri și procesarea datelor personale implicate?
Esta loja pede-te para aceitares cookies para efeitos de desempenho, redes sociais e publicidade. Os cookies de publicidade e de redes sociais de terceiros são utilizados para te oferecer funcionalidades sociais e anúncios personalizados. Aceitas estes cookies e o processamento de dados pessoais envolvidos?
Náš obchod používa súbory cookie za účelom zabezpečenia nevyhnutnej funkcionality stránok, sociálnych médií a marketingu. Súhlasíte s týmito súbormi cookies a spracovaním príslušných osobných údajov?
Deze winkel vraagt je om cookies te accepteren voor betere prestaties en voor sociale-media- en advertentiedoeleinden. Er worden sociale-media- en advertentiecookies van derden gebruikt om je sociale-mediafunctionaliteit en persoonlijke advertenties te bieden. Accepteer je deze cookies en de bijbehorende verwerking van je persoonsgegevens?
Für eine optimal Performance, eine reibungslose Verwendung sozialer Medien und aus Werbezwecken empfiehlt dir dieser Laden, der Verwendung von Cookies zuzustimmen. Durch Cookies von sozialen Medien und Werbecookies von Drittparteien hast du Zugriff auf Social-Media-Funktionen und erhältst personalisierte Werbung. Stimmst du der Verwendung dieser Cookies und der damit verbundenen Verarbeitung deiner persönlichen Daten zu?
Αυτό το κατάστημα σου ζητά να αποδεχτείς τα cookies για σκοπούς απόδοσης, κοινωνικής δικτύωσης και διαφήμισης. Τα cookies κοινωνικής δικτύωσης και διαφήμισης παρέχονται από τρίτα μέρη για να σου προσφέρουν λειτουργίες κοινωνικής δικτύωσης και εξατομικευμένες διαφημίσεις. Αποδέχεσαι αυτά τα cookies και την συνεπαγόμενη επεξεργασία προσωπικών δεδομένων;
';
+
+ // Italian
+ $langCode = 'it';
+ $cookiesDefault['title'][$langCode] = 'Impostazioni dei cookie';
+ $cookiesDefault['text'][$langCode] = '
Questo negozio richiede di accettare i cookie per scopi legati a prestazioni, social media e annunci pubblicitari. I cookie di terze parti per social media e a scopo pubblicitario vengono utilizzati per offrire funzionalità social e annunci pubblicitari personalizzati. Accetti i cookie e l\'elaborazione dei dati personali interessati?
Denna butik ber dig att godkänna cookies för anpassning av prestanda, sociala medier och marknadsföring. Tredjepartscookies för sociala medier och marknadsföring används för att erbjuda anpassade annonser och funktioner för sociala medier. Godkänner du dessa cookies och behandlingen av berörda personuppgifter?
';
+
+ // Dansk
+ $langCode = 'da';
+ $cookiesDefault['title'][$langCode] = 'Dine indstillinger for cookies';
+ $cookiesDefault['text'][$langCode] = '
Denne butik beder dig om at acceptere cookies til performance, sociale medier og reklameformål. Sociale medier og tredjeparts annoncecookies bruges til at tilbyde dig funktionaliteter og tilpassede annoncer på sociale medier. Vil du acceptere disse cookies og behandlingen af implicerede personoplysninger?
';
+
+ // Norsk
+ $langCode = 'no';
+ $cookiesDefault['title'][$langCode] = 'Dine innstillinger for informasjonskapsler';
+ $cookiesDefault['text'][$langCode] = '
Denne butikken spør om du godtar informasjonskapsler for ytelsesformål, sosiale medier og annonsering. Informasjonskapsler for sosiale medier og annonsering fra tredjeparter brukes for å tilby deg funksjoner på sosiale medier og tilpassede annonser. Godtar du disse informasjonskapslene og den involverte behandlingen av personopplysningene dine?
Společnost tento obchod žádá o tvůj souhlas s používáním souborů cookie pro účely výkonu, sociálních médií a reklamy. Sociální média a reklamní soubory cookie třetích stran používáme k tomu, abychom ti mohli nabízet funkce sociálních médií a přizpůsobenou reklamu. Další informace nebo doplnění nastavení získáš kliknutím na tlačítko „Více informací“ nebo otevřením nabídky „Nastavení souborů cookie“ v dolní části webové stránky. Podrobnější informace o souborech cookie a zpracování tvých osobních údajů najdeš v našich Zásadách ochrany osobních údajů a používání souborů cookie. Souhlasíš s používáním souborů cookie a zpracováním souvisejících osobních údajů?
Ez a bolt a megfelelő teljesítmény és a közösségimédia-funkciók biztosításához, valamint a hirdetések megjelenítéséhez kéri a cookie-k elfogadását. A harmadik felek közösségimédia- és hirdetési cookie-jai használatával biztosítunk közösségimédia-funkciókat, és jelenítünk meg személyre szabott reklámokat. Ha több információra van szükséged, vagy kiegészítenéd a beállításaidat, kattints a További információ gombra, vagy keresd fel a webhely alsó részéről elérhető Cookie-beállítások területet. A cookie-kkal kapcsolatos további információért, valamint a személyes adatok feldolgozásának ismertetéséért tekintsd meg Adatvédelmi és cookie-kra vonatkozó szabályzatunkat. Elfogadod ezeket a cookie-kat és az érintett személyes adatok feldolgozását?
';
+
+ $cookiesDefault['cookie'][CookiesPlusFinality::NECESSARY_COOKIE] = CookiesPlusFinality::getDefaultValues(CookiesPlusFinality::NECESSARY_COOKIE);
+ $cookiesDefault['cookie'][CookiesPlusFinality::PREFERENCE_COOKIE] = CookiesPlusFinality::getDefaultValues(CookiesPlusFinality::PREFERENCE_COOKIE);
+ $cookiesDefault['cookie'][CookiesPlusFinality::STATISTIC_COOKIE] = CookiesPlusFinality::getDefaultValues(CookiesPlusFinality::STATISTIC_COOKIE);
+ $cookiesDefault['cookie'][CookiesPlusFinality::MARKETING_COOKIE] = CookiesPlusFinality::getDefaultValues(CookiesPlusFinality::MARKETING_COOKIE);
+ // $cookiesDefault['cookie'][CookiesPlusFinality::UNCLASSIFIED_COOKIE] = CookiesPlusFinality::getDefaultValues(CookiesPlusFinality::UNCLASSIFIED_COOKIE);
+ // $cookiesDefault['cookie'][CookiesPlusFinality::PERFORMANCE_COOKIE] = CookiesPlusFinality::getDefaultValues(CookiesPlusFinality::PERFORMANCE_COOKIE);
+
+ $fields = [];
+ $languages = Language::getLanguages(false);
+ foreach ($languages as $lang) {
+ $languageCode = strtok($lang['language_code'], '-');
+
+ $fields['C_P_TITLE'][$lang['id_lang']] = (isset($cookiesDefault['title'][$languageCode]) && $cookiesDefault['title'][$languageCode]) ? $cookiesDefault['title'][$languageCode] : $cookiesDefault['title']['en'];
+ $fields['C_P_TEXT_BASIC'][$lang['id_lang']] = (isset($cookiesDefault['text'][$languageCode]) && $cookiesDefault['text'][$languageCode]) ? $cookiesDefault['text'][$languageCode] : $cookiesDefault['text']['en'];
+ }
+
+ Configuration::updateValue('C_P_TITLE', $fields['C_P_TITLE'], true);
+ Configuration::updateValue('C_P_TEXT_BASIC', $fields['C_P_TEXT_BASIC'], true);
+
+ $modules = Module::getModulesOnDisk(true);
+ if (Shop::isFeatureActive()) {
+ $shops = Shop::getShops(false, null, true);
+ } else {
+ $shops = [1];
+ }
+
+ foreach ($shops as $shop) {
+ foreach ($cookiesDefault['cookie'] as $cookiesPlusFinalityId => $cookieDefault) {
+ $cookiesPlusFinality = new CookiesPlusFinality();
+ $cookiesPlusFinality->id_shop = $shop;
+ $cookiesPlusFinality->technical = (isset($cookieDefault['technical']) && $cookieDefault['technical']) ? $cookieDefault['technical'] : 0;
+ $cookiesPlusFinality->active = (isset($cookieDefault['active']) && $cookieDefault['active']) ? $cookieDefault['active'] : 0;
+ $cookiesPlusFinality->position = $cookieDefault['position'];
+
+ if (isset($cookieDefault['modules']) && $cookieDefault['modules']) {
+ $modulesIds = [];
+ foreach ($modules as $module) {
+ if ($module->installed && in_array($module->name, $cookieDefault['modules'])) {
+ $modulesIds[] = $module->id;
+ }
+ }
+
+ $cookiesPlusFinality->modules = json_encode($modulesIds);
+
+ // If store has any of the modules, enable this finality
+ if ($modulesIds) {
+ $cookiesPlusFinality->active = 1;
+ }
+ }
+
+ foreach ($languages as $lang) {
+ $languageCode = strtok($lang['language_code'], '-');
+ $cookiesPlusFinality->name[$lang['id_lang']] = (isset($cookieDefault['name'][$languageCode]) && $cookieDefault['name'][$languageCode]) ? $cookieDefault['name'][$languageCode] : $cookieDefault['name']['en'];
+ $cookiesPlusFinality->description[$lang['id_lang']] = (isset($cookieDefault['description'][$languageCode]) && $cookieDefault['description'][$languageCode]) ? $cookieDefault['description'][$languageCode] : $cookieDefault['description']['en'];
+ }
+
+ $result = $cookiesPlusFinality->save();
+
+ if ($cookiesPlusFinalityId === CookiesPlusFinality::STATISTIC_COOKIE) {
+ $cookiesPlusStatisticFinalityId = $cookiesPlusFinality->id;
+ }
+
+ if ($cookiesPlusFinalityId === CookiesPlusFinality::MARKETING_COOKIE) {
+ $cookiesPlusMarketingFinalityId = $cookiesPlusFinality->id;
+ }
+
+ if (!$result) {
+ return false;
+ }
+
+ if (isset($cookieDefault['cookies']) && $cookieDefault['cookies']) {
+ foreach ($cookieDefault['cookies'] as $cookie) {
+ $cookiesPlusCookie = new CookiesPlusCookie();
+ $cookiesPlusCookie->id_shop = $shop;
+ $cookiesPlusCookie->id_cookiesplus_finality = $cookiesPlusFinality->id;
+ $cookiesPlusCookie->active = $cookie['active'];
+
+ $cookiesPlusCookie->name = $cookie['name'];
+ $cookiesPlusCookie->provider = isset($cookie['provider']) ? $cookie['provider'] : '';
+ $cookiesPlusCookie->provider_url = isset($cookie['provider_url']) ? $cookie['provider_url'] : '';
+
+ // If store has any of the modules, enable this finality
+ if (isset($cookie['modules']) && $cookie['modules']) {
+ foreach ($modules as $module) {
+ if ($module->installed && isset($module->name) && in_array($module->name, $cookie['modules'])) {
+ $cookiesPlusCookie->active = 1;
+ $cookiesPlusFinality = new CookiesPlusFinality($cookiesPlusFinality->id);
+ $cookiesPlusFinality->active = 1;
+ // $cookiesPlusFinality->save();
+ break;
+ }
+ }
+ }
+
+ foreach ($languages as $lang) {
+ $languageCode = strtok($lang['language_code'], '-');
+
+ if (isset($cookie['purpose']['en'])) {
+ $cookiesPlusCookie->purpose[$lang['id_lang']] = (isset($cookie['purpose'][$languageCode]) && $cookie['purpose'][$languageCode]) ? $cookie['purpose'][$languageCode] : $cookie['purpose']['en'];
+ }
+
+ if (isset($cookie['expiry']['en'])) {
+ $cookiesPlusCookie->expiry[$lang['id_lang']] = (isset($cookie['expiry'][$languageCode]) && $cookie['expiry'][$languageCode]) ? $cookie['expiry'][$languageCode] : $cookie['expiry']['en'];
+ }
+ }
+
+ $cookiesPlusCookie->save();
+ }
+ }
+ }
+
+ // GTM
+ $gtm = [
+ $cookiesPlusStatisticFinalityId => [
+ 'cookiesPlusFinality' => $cookiesPlusStatisticFinalityId,
+ 'gtmFinality' => [
+ 'analytics_storage' => true,
+ ],
+ 'firingEvent' => '',
+ ],
+ $cookiesPlusMarketingFinalityId => [
+ 'cookiesPlusFinality' => $cookiesPlusMarketingFinalityId,
+ 'gtmFinality' => [
+ 'ad_storage' => true,
+ 'ad_user_data' => true,
+ 'ad_personalization' => true,
+ ],
+ 'firingEvent' => '',
+ ],
+ ];
+ $gtm = json_encode($gtm);
+ Configuration::updateValue('C_P_GTM_CONSENT', $gtm, false, null, $shop);
+ }
+
+ return true;
+ }
+
+ public function getContent()
+ {
+ Tools::redirectAdmin('index.php?controller=AdminCookiesPlusConfiguration&token=' . Tools::getAdminTokenLite('AdminCookiesPlusConfiguration'));
+ }
+
+ public function getWarnings($getAll = true)
+ {
+ $warnings = [];
+
+ if (Configuration::get('PS_DISABLE_NON_NATIVE_MODULE')) {
+ $warnings[] = sprintf($this->l('%1$s "%2$s" at %3$s - %4$s'), $this->l('Disable'), $this->l('Disable non PrestaShop modules'), $this->l('Advanced Parameters'), $this->l('Performance'));
+ }
+
+ if (Configuration::get('PS_DISABLE_OVERRIDES')) {
+ $warnings[] = sprintf($this->l('%1$s "%2$s" at %3$s - %4$s'), $this->l('Disable'), $this->l('Disable all overrides'), $this->l('Advanced Parameters'), $this->l('Performance'));
+ }
+
+ $cookiesPlusFinalitiesList = CookiesPlusFinality::getCookiesPlusFinalities();
+ $atLeastOneFinalityNonTechnical = false;
+ $atLeastOneFinalityTechnical = false;
+ foreach ($cookiesPlusFinalitiesList as $cookiesPlusFinality) {
+ if ($cookiesPlusFinality['active'] && $cookiesPlusFinality['technical']) {
+ $atLeastOneFinalityTechnical = true;
+ }
+
+ if ($cookiesPlusFinality['active'] && !$cookiesPlusFinality['technical']) {
+ $atLeastOneFinalityNonTechnical = true;
+ }
+ }
+
+ // If there's any technical cookie finality enabled
+ if (!$atLeastOneFinalityTechnical) {
+ $warnings[] = $this->l('Please check "Cookie finalities". You need to enable at least one technical cookie finality.');
+ }
+
+ // If there's only technical cookies, there's no need to display the warnings
+ if (!$atLeastOneFinalityNonTechnical) {
+ $warnings[] = $this->l('Please check "Cookie finalities". You need to enable at least one non-technical cookie finality. If there\'s only technical cookies finalities enabled, the cookie notice will not be displayed');
+ }
+
+ /*if (Module::isInstalled('litespeedcache')) {
+ $warnings[] = $this->l('It seems that you are using litespeedcache cache. An additional configuration in this module may be required.');
+ }
+
+ if (Module::isInstalled('stadvancedcache')) {
+ $warnings[] = $this->l('It seems that you are using stadvancedcache cache. An additional configuration in this module may be required.');
+ }
+
+ if (Module::isInstalled('jprestaspeedpack')) {
+ $warnings[] = $this->l('It seems that you are using jprestaspeedpack cache. An additional configuration in this module may be required.');
+ }*/
+ if (Module::isInstalled('litespeedcache')
+ || Module::isInstalled('stadvancedcache')
+ || Module::isInstalled('jprestaspeedpack')
+ || Module::isInstalled('pagecache')) {
+ $warnings[] = $this->l('If you are using a cache module please ensure that the cookies module is working correctly.');
+ }
+
+ if (count($warnings) && version_compare(_PS_VERSION_, '1.6.1', '<')) {
+ return $warnings[0];
+ }
+
+ if (!$getAll && count($warnings)) {
+ return $warnings[0];
+ }
+
+ return $warnings;
+ }
+
+ public function getModuleList()
+ {
+ $query = 'SELECT m.`id_module`, m.`name`
+ FROM `' . _DB_PREFIX_ . 'module` m';
+
+ $module_list = Db::getInstance()->executeS($query);
+
+ foreach ($module_list as $key => &$module) {
+ $module['displayName'] = Module::getModuleName($module['name']);
+
+ if ((int) $module['id_module'] === 0) {
+ unset($module_list[$key]);
+ }
+
+ if ($module['name'] === $this->name) {
+ unset($module_list[$key]);
+ }
+ }
+ unset($module);
+
+ usort($module_list, static function ($a, $b) {
+ return strnatcasecmp($a['displayName'], $b['displayName']);
+ });
+
+ return $module_list;
+ }
+
+ protected static function executeModule()
+ {
+ if (!Configuration::get('C_P_ENABLE')) {
+ return false;
+ }
+
+ // Validate allowed IPs
+ if (Configuration::get('C_P_DEBUG') && !self::onlyIPDebug()) {
+ return false;
+ }
+
+ // Validate user agent
+ if (self::byPassUserAgent()) {
+ return false;
+ }
+
+ // Validate disallow IPs
+ if (self::bypassIP()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected static function getGeo()
+ {
+ // Don't display outside EU
+ if (Configuration::get('PS_GEOLOCATION_ENABLED')
+ && !Configuration::get('C_P_GEO')
+ && !in_array(Tools::getRemoteAddr(), ['localhost', '127.0.0.1', '::1'])) {
+ // Check if Maxmind Database exists
+ if (@filemtime(_PS_GEOIP_DIR_ . _PS_GEOIP_CITY_FILE_)) {
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ include_once _PS_GEOIP_DIR_ . 'geoipcity.inc';
+
+ $gi = geoip_open(realpath(_PS_GEOIP_DIR_ . _PS_GEOIP_CITY_FILE_), GEOIP_STANDARD);
+ $record = geoip_record_by_addr($gi, Tools::getRemoteAddr());
+
+ if (is_object($record)
+ && $record->continent_code
+ && $record->continent_code !== 'EU') {
+ return false;
+ }
+ } else {
+ $reader = new GeoIp2\Database\Reader(_PS_GEOIP_DIR_ . _PS_GEOIP_CITY_FILE_);
+ try {
+ $record = $reader->city(Tools::getRemoteAddr());
+ } catch (GeoIp2\Exception\AddressNotFoundException $e) {
+ $record = null;
+ }
+
+ if (is_object($record)
+ && $record->continent->code
+ && $record->continent->code !== 'EU') {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ protected static function byPassUserAgent()
+ {
+ if (isset($_SERVER['HTTP_USER_AGENT'])
+ && Configuration::get('C_P_BOTS')
+ && preg_match('/' . Configuration::get('C_P_BOTS') . '/i', $_SERVER['HTTP_USER_AGENT'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected static function bypassIP()
+ {
+ if (Configuration::get('C_P_IPS')
+ && in_array(Tools::getRemoteAddr(), explode('|', Configuration::get('C_P_IPS')))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected static function onlyIPDebug()
+ {
+ if (!Configuration::get('C_P_IPS_DEBUG')) {
+ return true;
+ }
+
+ if (in_array(Tools::getRemoteAddr(), explode('|', Configuration::get('C_P_IPS_DEBUG')))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public function getCookiesPlusCookiesList()
+ {
+ $idCookiesPlusFinality = (int) Tools::getValue('id_cookiesplus_finality');
+
+ if (!Tools::getIsset('addcookiesplus_finality') && !$idCookiesPlusFinality) {
+ return $this->displayError('Error loading cookies');
+ }
+
+ $cookiesPlusCookiesList = CookiesPlusCookie::getCookiesPlusCookies($idCookiesPlusFinality, null, false, $this->context->shop->id);
+
+ $fields_list = [
+ 'active' => [
+ 'title' => $this->l('Enabled'),
+ 'active' => 'active',
+ 'type' => 'bool',
+ ],
+ 'name' => [
+ 'title' => $this->l('Cookie name'),
+ 'filter_key' => 'a!name',
+ ],
+ 'provider' => [
+ 'title' => $this->l('Provider'),
+ ],
+ 'purpose' => [
+ 'title' => $this->l('Purpose'),
+ 'callback' => 'getCookiePurposeCallback',
+ 'callback_object' => 'CookiesPlusCookie',
+ ],
+ 'expiry' => [
+ 'title' => $this->l('Expiry'),
+ ],
+ ];
+
+ $helperList = new HelperList();
+
+ $helperList->shopLinkType = '';
+ $helperList->simple_header = false;
+ $helperList->show_toolbar = true;
+ $helperList->module = $this;
+ $helperList->actions = ['edit', 'deletecookie'];
+ $helperList->identifier = 'id_cookiesplus_cookie';
+ $helperList->table = 'cookiesplus_cookie';
+ $helperList->token = Tools::getAdminTokenLite('AdminCookiesPlusCookies');
+ $helperList->currentIndex = $this->context->link->getAdminLink('AdminCookiesPlusCookies', false) . '&back=1&id_cookiesplus_finality=' . (int) Tools::getValue('id_cookiesplus_finality');
+
+ $helperList->title = $this->l('Cookies detail');
+
+ if (!Tools::getIsset('addcookiesplus_finality')) {
+ $helperList->toolbar_btn['new'] = [
+ 'href' => $helperList->currentIndex . '&add' . $helperList->table . '&token=' . $helperList->token . '&id_cookiesplus_finality=' . Tools::getValue('id_cookiesplus_finality'),
+ 'desc' => $this->l('Add new'),
+ ];
+ }
+
+ $helperList->listTotal = count($cookiesPlusCookiesList);
+
+ return $helperList->generateList($cookiesPlusCookiesList, $fields_list);
+ }
+
+ public function displayDeleteCookieLink($token = null, $id = null, $name = null)
+ {
+ $tpl = $this->context->smarty->createTemplate('helpers/list/list_action_delete.tpl');
+
+ $tpl->assign([
+ 'href' => $this->context->link->getAdminLink('AdminCookiesPlusCookies', false) . '&id_cookiesplus_cookie=' . $id . '&deletecookiesplus_cookie&token=' . $token,
+ 'confirm' => $this->l('Delete the selected item?') . $name,
+ 'action' => $this->l('Delete'),
+ 'consent_hash' => $id,
+ ]);
+
+ return $tpl->fetch();
+ }
+
+ /* Hooks */
+ public function hookDisplayAfterTitle($params)
+ {
+ return $this->hookDisplayAfterTitleTag($params);
+ }
+
+ public function hookDisplayAfterTitleTag()
+ {
+ if (Module::isInstalled('cdc_googletagmanager')) {
+ $html = '';
+
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ $cookiesPlusCookiePreferences = self::getCookiesPlusCookiePreferences();
+
+ $gtmConsents = json_decode(Configuration::get('C_P_GTM_CONSENT'), true);
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities((int) $this->context->language->id, true);
+ $gtm = [];
+ foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ $index = 'cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality'];
+ if (isset($cookiesPlusCookiePreferences[$index], $gtmConsents[(int) $cookiesPlusFinality['id_cookiesplus_finality']])) {
+ if (!isset($gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'])) {
+ continue;
+ }
+ foreach (array_keys($gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality']) as $gtmFinality) {
+ if ($cookiesPlusCookiePreferences[$index] === 'on') {
+ if (isset($gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'][$gtmFinality])
+ && $gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'][$gtmFinality]) {
+ $gtm[(int)$cookiesPlusFinality['id_cookiesplus_finality']][$gtmFinality] = true;
+ } else {
+ $gtm[(int)$cookiesPlusFinality['id_cookiesplus_finality']][$gtmFinality] = false;
+ }
+
+ } else {
+ $gtm[(int)$cookiesPlusFinality['id_cookiesplus_finality']][$gtmFinality] = false;
+ }
+ }
+ }
+ }
+
+ $this->context->smarty->assign([
+ 'gtm' => $gtm,
+ ]);
+
+ $html .= $this->context->smarty->fetch($this->local_path . 'views/templates/hook/gtm_consentmode.tpl');
+ }
+
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ $html .= Configuration::get('C_P_GTM_HEAD');
+ } else {
+ $random = Tools::substr(md5(microtime()), 0, 10);
+ $divName = 'hookDisplayAfterTitleTag_' . $this->id . '_' . $random;
+
+ $this->context->smarty->assign([
+ 'divName' => $divName,
+ 'id_module' => $this->id,
+ 'finalities' => implode(',', array_keys(json_decode(Configuration::get('C_P_GTM_FIRE_CONSENT'), true) ?? []) ?: []),
+ 'script' => json_encode(Configuration::get('C_P_GTM_HEAD')),
+ 'js' => '[]',
+ 'css' => '[]',
+ ]);
+
+ $html .= $this->context->smarty->fetch($this->local_path . 'views/templates/hook/hookmoduledata.tpl');
+ }
+
+ return $html;
+ }
+ }
+
+ /* Don't place in this header anything that can NOT be cachable */
+ public function hookHeader()
+ {
+ return $this->hookDisplayHeader();
+ }
+
+ public function hookDisplayHeader()
+ {
+ $cookiesPlusCookiePreferences = self::getCookiesPlusCookiePreferences();
+ if (isset($cookiesPlusCookiePreferences['consent_date'])
+ && date('Y-m-d H:i', strtotime(Configuration::get('C_P_REVOKE_CONSENT'))) > date('Y-m-d H:i', strtotime($cookiesPlusCookiePreferences['consent_date']))) {
+ $this->resetCookiesPlusPreferences();
+ }
+
+ // Check if consent file exists
+ if (Configuration::get('C_P_SAVE_CONSENT')) {
+ if (isset($cookiesPlusCookiePreferences['consent_hash'])) {
+ if (!CookiesPlusUserConsent::getCookiesPlusUserConsentDataByHash($cookiesPlusCookiePreferences['consent_hash'])) {
+ $this->resetCookiesPlusPreferences();
+ }
+ }
+ }
+
+ $this->context->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/cookiesplus.css');
+ if (Configuration::get('C_P_MATERIAL_ICONS')) {
+ $this->context->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/cookiesplus-material-icons.css');
+ // $html .= '';
+ }
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ $this->context->controller->addJS(_MODULE_DIR_ . $this->name . '/views/js/cookiesplus-front.js');
+ } else {
+ $this->context->controller->registerJavascript(
+ 'cookiesplus-front',
+ 'modules/' . $this->name . '/views/js/cookiesplus-front.js',
+ [
+ 'attributes' => 'async',
+ ]
+ );
+ }
+
+ // Just assign to smarty, in case user add an IF condition in template for a custom script
+ $this->context->smarty->assign([
+ 'C_P_COOKIE_VALUE' => (array) $cookiesPlusCookiePreferences,
+ ]);
+
+ $this->context->smarty->assign([
+ 'C_P_CSS' => Configuration::get('C_P_CSS'),
+ 'C_P_BACKGROUND_COLOR' => Configuration::get('C_P_BACKGROUND_COLOR'),
+ 'C_P_FONT_COLOR' => Configuration::get('C_P_FONT_COLOR'),
+ 'C_P_BUTTON_POSITION' => Configuration::get('C_P_BUTTON_POSITION'),
+ 'C_P_ACCEPT_DISPLAY' => Configuration::get('C_P_ACCEPT_DISPLAY'),
+ 'C_P_ACCEPT_BACKGROUND_COLOR' => Configuration::get('C_P_ACCEPT_BACKGROUND_COLOR'),
+ 'C_P_ACCEPT_BORDER_COLOR' => Configuration::get('C_P_ACCEPT_BORDER_COLOR'),
+ 'C_P_ACCEPT_FONT_COLOR' => Configuration::get('C_P_ACCEPT_FONT_COLOR'),
+ 'C_P_ACCEPT_FONT_SIZE' => Configuration::get('C_P_ACCEPT_FONT_SIZE'),
+ 'C_P_ACCEPT_PADDING' => Configuration::get('C_P_ACCEPT_PADDING'),
+ 'C_P_MORE_INFO_DISPLAY' => Configuration::get('C_P_MORE_INFO_DISPLAY'),
+ 'C_P_MORE_INFO_BACKGROUND_COLOR' => Configuration::get('C_P_MORE_INFO_BACKGROUND_COLOR'),
+ 'C_P_MORE_INFO_BORDER_COLOR' => Configuration::get('C_P_MORE_INFO_BORDER_COLOR'),
+ 'C_P_MORE_INFO_FONT_COLOR' => Configuration::get('C_P_MORE_INFO_FONT_COLOR'),
+ 'C_P_MORE_INFO_FONT_SIZE' => Configuration::get('C_P_MORE_INFO_FONT_SIZE'),
+ 'C_P_MORE_INFO_PADDING' => Configuration::get('C_P_MORE_INFO_PADDING'),
+ 'C_P_REJECT_DISPLAY' => Configuration::get('C_P_REJECT_DISPLAY'),
+ 'C_P_REJECT_BACKGROUND_COLOR' => Configuration::get('C_P_REJECT_BACKGROUND_COLOR'),
+ 'C_P_REJECT_BORDER_COLOR' => Configuration::get('C_P_REJECT_BORDER_COLOR'),
+ 'C_P_REJECT_FONT_COLOR' => Configuration::get('C_P_REJECT_FONT_COLOR'),
+ 'C_P_REJECT_FONT_SIZE' => Configuration::get('C_P_REJECT_FONT_SIZE'),
+ 'C_P_REJECT_PADDING' => Configuration::get('C_P_REJECT_PADDING'),
+ 'C_P_SAVE_BACKGROUND_COLOR' => Configuration::get('C_P_SAVE_BACKGROUND_COLOR'),
+ 'C_P_SAVE_BORDER_COLOR' => Configuration::get('C_P_SAVE_BORDER_COLOR'),
+ 'C_P_SAVE_FONT_COLOR' => Configuration::get('C_P_SAVE_FONT_COLOR'),
+ 'C_P_SAVE_FONT_SIZE' => Configuration::get('C_P_SAVE_FONT_SIZE'),
+ 'C_P_SAVE_PADDING' => Configuration::get('C_P_SAVE_PADDING'),
+ 'C_P_MATERIAL_ICONS_LIBRARY' => Configuration::get('C_P_MATERIAL_ICONS_LIBRARY'),
+ 'C_P_ICONS' => Configuration::get('C_P_ICONS'),
+ 'C_P_TAB_ENABLED' => Configuration::get('C_P_TAB_ENABLED'),
+ 'C_P_TAB_POSITION' => Configuration::get('C_P_TAB_POSITION'),
+ 'C_P_TAB_BACKGROUND_COLOR' => Configuration::get('C_P_TAB_BACKGROUND_COLOR'),
+ 'C_P_TAB_FONT_COLOR' => Configuration::get('C_P_TAB_FONT_COLOR'),
+ ]);
+
+ $html = $this->context->smarty->fetch($this->local_path . 'views/templates/hook/cookies-style.tpl');
+
+ if (!Module::isInstalled('cdc_googletagmanager')) {
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ $gtmConsents = json_decode(Configuration::get('C_P_GTM_CONSENT'), true);
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities((int) $this->context->language->id, true);
+ $gtm = [];
+ foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ $index = 'cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality'];
+ if (isset($cookiesPlusCookiePreferences[$index], $gtmConsents[(int) $cookiesPlusFinality['id_cookiesplus_finality']])) {
+ if (!isset($gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'])) {
+ continue;
+ }
+ foreach (array_keys($gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality']) as $gtmFinality) {
+ if ($cookiesPlusCookiePreferences[$index] === 'on') {
+ if (isset($gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'][$gtmFinality])
+ && $gtmConsents[(int)$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'][$gtmFinality]) {
+ $gtm[(int)$cookiesPlusFinality['id_cookiesplus_finality']][$gtmFinality] = true;
+ } else {
+ $gtm[(int)$cookiesPlusFinality['id_cookiesplus_finality']][$gtmFinality] = false;
+ }
+
+ } else {
+ $gtm[(int)$cookiesPlusFinality['id_cookiesplus_finality']][$gtmFinality] = false;
+ }
+ }
+ }
+ }
+
+ if (!empty($gtm)) {
+ $this->context->smarty->assign([
+ 'gtm' => call_user_func_array('array_merge', $gtm),
+ ]);
+ }
+
+ $html .= $this->context->smarty->fetch($this->local_path . 'views/templates/hook/gtm_consentmode.tpl');
+ }
+
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ $html .= Configuration::get('C_P_GTM_HEAD');
+ } elseif (Configuration::get('C_P_GTM_FIRE_CONSENT')) {
+ $random = Tools::substr(md5(microtime()), 0, 10);
+ $divName = 'hookDisplayHeader' . $this->id . '_' . $random;
+
+ $this->context->smarty->assign([
+ 'divName' => $divName,
+ 'id_module' => $this->id,
+ 'finalities' => implode(',', array_keys(json_decode(Configuration::get('C_P_GTM_FIRE_CONSENT'), true)) ?: []),
+ 'script' => json_encode(Configuration::get('C_P_GTM_HEAD')),
+ 'js' => '[]',
+ 'css' => '[]',
+ ]);
+
+ $html .= $this->context->smarty->fetch($this->local_path . 'views/templates/hook/hookmoduledata.tpl');
+ }
+ }
+
+ return $html;
+ }
+
+ public function hookDisplayAfterBodyOpeningTag()
+ {
+ $html = '';
+
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ $html .= Configuration::get('C_P_GTM_BODY');
+ } elseif (Configuration::get('C_P_GTM_FIRE_CONSENT')) {
+ $random = Tools::substr(md5(microtime()), 0, 10);
+ $divName = 'hookDisplayAfterBodyOpeningTag_' . $this->id . '_' . $random;
+
+ $this->context->smarty->assign([
+ 'divName' => $divName,
+ 'id_module' => $this->id,
+ 'finalities' => implode(',', array_keys(json_decode(Configuration::get('C_P_GTM_FIRE_CONSENT'), true)) ?: []),
+ 'script' => json_encode(Configuration::get('C_P_GTM_HEAD')),
+ 'js' => '[]',
+ 'css' => '[]',
+ ]);
+
+ $html .= $this->context->smarty->fetch($this->local_path . 'views/templates/hook/hookmoduledata.tpl');
+ }
+
+ return $html;
+ }
+
+ public function hookDisplayCookiesHeader()
+ {
+ $this->hookDisplayHeader();
+ }
+
+ public function hookFooter()
+ {
+ $html = null;
+
+ $cookiesPlusPreferences = self::getCookiesPlusCookiePreferences();
+
+ // Don't display modal with Creative Elements editor
+ /*if (Tools::isSubmit('cp_type')) {
+ $displayModal = false;
+ }*/
+ // Get scripts from all finalities
+ $script = [];
+ $scriptNot = [];
+ $cookies = [];
+ $gtm = [];
+ $fb = [];
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ $gtmConsents = json_decode(Configuration::get('C_P_GTM_CONSENT'), true);
+ }
+ if (Configuration::get('C_P_FB_ENABLE')) {
+ $fbConsents = json_decode(Configuration::get('C_P_FB_CONSENT'), true);
+ }
+
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities((int) $this->context->language->id, true);
+ // $atLeastOneFinalityNonTechnical = false;
+ foreach ($cookiesPlusFinalities as &$cookiesPlusFinality) {
+ $cookiesPlusFinality['cookies'] = CookiesPlusCookie::getCookiesPlusCookies($cookiesPlusFinality['id_cookiesplus_finality'], (int) $this->context->language->id, true, $this->context->shop->id);
+ /*if ($cookiesPlusFinality['active'] && !$cookiesPlusFinality['technical']) {
+ $atLeastOneFinalityNonTechnical = true;
+ }*/
+ if ($cookiesPlusFinality['js_script']) {
+ // Strip #', '$1', $cookiesPlusFinality['js_script']);
+
+ // Escape all chars
+ // $cookiesPlusFinality['js_script'] = str_replace('"', "'", $cookiesPlusFinality['js_script']);
+
+ /*$escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c", "'",);
+ $replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b", "\'");
+ $cookiesPlusFinality['js_script'] = str_replace($escapers, $replacements, $cookiesPlusFinality['js_script']);*/
+ // $cookiesPlusFinality['js_script'] = str_replace("\r", "\\r", $cookiesPlusFinality['js_script']);
+ // $cookiesPlusFinality['js_script'] = str_replace("\n", "\\n", $cookiesPlusFinality['js_script']);
+
+ // remove comments
+ // $cookiesPlusFinality['js_script'] = preg_replace('//', '', $cookiesPlusFinality['js_script']);
+
+ // remove tabs, spaces, newlines, etc.
+ // $cookiesPlusFinality['js_script'] = str_replace(array(PHP_EOL, "\t"), '', $cookiesPlusFinality['js_script']);
+ // $cookiesPlusFinality['js_script'] = preg_replace('/\v(?:[\v\h]+)/', '', $cookiesPlusFinality['js_script']);
+ /*$cookiesPlusFinality['js_script'] = str_replace("\n", '', $cookiesPlusFinality['js_script']);
+ $cookiesPlusFinality['js_script'] = str_replace("\r", '', $cookiesPlusFinality['js_script']);
+ $cookiesPlusFinality['js_script'] = str_replace("\t", '', $cookiesPlusFinality['js_script']);*/
+ // remove all spaces
+ // $cookiesPlusFinality['js_script'] = preg_replace('|\s\s+|', ' ', $cookiesPlusFinality['js_script']);
+
+ // Minify fails with
+ /*if (version_compare(_PS_VERSION_, '1.7', '>')) {
+ $script[(int)$cookiesPlusFinality['id_cookiesplus_finality']] = JSMin::minify($cookiesPlusFinality['js_script']);
+ } else {
+ $script[(int)$cookiesPlusFinality['id_cookiesplus_finality']] = $cookiesPlusFinality['js_script'];
+ }*/
+ $script[(int) $cookiesPlusFinality['id_cookiesplus_finality']] = $cookiesPlusFinality['js_script'];
+ }
+
+ if ($cookiesPlusFinality['js_not_script']) {
+ $scriptNot[(int) $cookiesPlusFinality['id_cookiesplus_finality']] = $cookiesPlusFinality['js_not_script'];
+ }
+
+ if ($cookiesPlusFinality['cookies']) {
+ $cookies[(int) $cookiesPlusFinality['id_cookiesplus_finality']] = $cookiesPlusFinality['cookies'];
+ }
+
+ if (Configuration::get('C_P_GTM_ENABLE')) {
+ if ($cookiesPlusFinality['technical']) {
+ continue;
+ }
+
+ if (isset($gtmConsents[(int) $cookiesPlusFinality['id_cookiesplus_finality']])) {
+ if (isset($gtmConsents[(int) $cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'])
+ && $gtmConsents[(int) $cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality']) {
+ $gtm[(int) $cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'] = $gtmConsents[$cookiesPlusFinality['id_cookiesplus_finality']]['gtmFinality'];
+ $gtm[(int) $cookiesPlusFinality['id_cookiesplus_finality']]['firingEvent'] = $gtmConsents[$cookiesPlusFinality['id_cookiesplus_finality']]['firingEvent'];
+ }
+ }
+ }
+
+ if (Configuration::get('C_P_FB_ENABLE')) {
+ if ($cookiesPlusFinality['technical']) {
+ continue;
+ }
+
+ if (isset($fbConsents[(int) $cookiesPlusFinality['id_cookiesplus_finality']])) {
+ $fb[(int) $cookiesPlusFinality['id_cookiesplus_finality']] = 'true';
+ }
+ }
+ }
+ unset($cookiesPlusFinality);
+
+ // If there's only technical cookies, there's no need to display the warning
+ /*if (!$atLeastOneFinalityNonTechnical) {
+ $displayModal = false;
+ }*/
+ $script = json_encode($script);
+ $script = self::sanitizeJson($script);
+
+ $scriptNot = json_encode($scriptNot);
+ $scriptNot = self::sanitizeJson($scriptNot);
+
+ $cookies = json_encode($cookies);
+ $cookies = self::sanitizeJson($cookies);
+
+ $gtm = json_encode($gtm);
+ $gtm = self::sanitizeJson($gtm);
+
+ $fb = json_encode($fb);
+ $fb = self::sanitizeJson($fb);
+
+ /*$cookie = array();
+ if (isset($_COOKIE['cookiesplus'])) {
+ $cookie = json_decode($_COOKIE['cookiesplus'], true);
+ }
+
+ $cookieExpiryTime = time() + Configuration::get('C_P_EXPIRY') * 86400;
+ setcookie('cookiesplus', json_encode($cookie), $cookieExpiryTime, '/');
+*/
+ $this->context->smarty->assign([
+ 'C_P_REFRESH' => Configuration::get('C_P_REFRESH'),
+ 'C_P_EXPIRY' => Configuration::get('C_P_EXPIRY') ?: 365,
+ 'C_P_CMS_PAGE' => (int) Configuration::get('C_P_CMS_PAGE'),
+ 'C_P_DATE' => date('Y-m-d H:i', time()),
+ 'C_P_COOKIE_VALUE_JSON' => $cookiesPlusPreferences ? json_encode($cookiesPlusPreferences) : '{}', // empty JSON
+ 'C_P_OVERLAY' => Configuration::get('C_P_OVERLAY'),
+ 'C_P_OVERLAY_OPACITY' => Configuration::get('C_P_OVERLAY_OPACITY'),
+ 'C_P_NOT_AVAILABLE_OUTSIDE_EU' => self::getGeo(), // Don't display modal outside EU
+ 'C_P_FINALITIES_COUNT' => count($cookiesPlusFinalities),
+ 'C_P_SCRIPT' => $script,
+ 'C_P_SCRIPT_NOT' => $scriptNot,
+ 'C_P_COOKIES' => $cookies,
+ 'C_P_GTM' => $gtm,
+ 'C_P_FB' => $fb,
+ ]);
+
+ $html .= $this->context->smarty->fetch($this->local_path . 'views/templates/hook/cookies-notice-vars.tpl');
+
+ if (!self::executeModule()) {
+ return $html;
+ }
+
+ $cpClass = '';
+ if (Configuration::get('C_P_WIDTH') == '100') {
+ $cpClass = 'col-12 col-xs-12';
+ } elseif (Configuration::get('C_P_WIDTH') == '75') {
+ if (Configuration::get('C_P_BUTTON_POSITION') == '2') {
+ $cpClass = 'col-11 col-xs-11 col-md-9';
+ } else {
+ $cpClass = 'col-12 col-xs-12 col-md-9';
+ }
+ } elseif (Configuration::get('C_P_WIDTH') == '50') {
+ if (Configuration::get('C_P_BUTTON_POSITION') == '2') {
+ $cpClass = 'col-11 col-xs-11 col-md-9 col-xl-6';
+ } else {
+ $cpClass = 'col-12 col-xs-12 col-md-9 col-lg-6';
+ }
+ } elseif ((int) Configuration::get('C_P_WIDTH') === 25) {
+ $cpClass = 'col-12 col-xs-12 col-md-6 col-lg-4 col-xl-3';
+ }
+
+ if ($this->context->language->id) {
+ $idLang = $this->context->language->id;
+ } elseif ($this->context->cookie->id_lang) {
+ $idLang = $this->context->cookie->id_lang;
+ } else {
+ $idLang = (int) Configuration::get('PS_LANG_DEFAULT');
+ }
+
+ $this->context->smarty->assign([
+ 'link' => Context::getContext()->link,
+ 'C_P_COOKIE_VALUE' => (array) $cookiesPlusPreferences,
+ 'C_P_POSITION' => Configuration::get('C_P_POSITION'),
+ 'C_P_WIDTH' => Configuration::get('C_P_WIDTH'),
+ 'C_P_CLASS' => $cpClass,
+ 'C_P_BACKGROUND_COLOR' => Configuration::get('C_P_BACKGROUND_COLOR'),
+ 'C_P_FONT_COLOR' => Configuration::get('C_P_FONT_COLOR'),
+ 'C_P_DISPLAY_TITLE' => Configuration::get('C_P_DISPLAY_TITLE'),
+ 'C_P_TITLE' => Configuration::get('C_P_TITLE', $idLang),
+ 'C_P_JS' => Configuration::get('C_P_JS'),
+ 'C_P_TEXT_BASIC' => Configuration::get('C_P_TEXT_BASIC', $idLang),
+ 'C_P_TEXT_REQUIRED' => Configuration::get('C_P_TEXT_REQUIRED', $idLang),
+ 'C_P_TEXT_3RDPARTY' => Configuration::get('C_P_TEXT_3RDPARTY', $idLang),
+ 'C_P_CMS_PAGE' => Configuration::get('C_P_CMS_PAGE'),
+ 'C_P_BUTTON_POSITION' => Configuration::get('C_P_BUTTON_POSITION'),
+ 'C_P_ACCEPT_DISPLAY' => Configuration::get('C_P_ACCEPT_DISPLAY'),
+ 'C_P_ACCEPT_BACKGROUND_COLOR' => Configuration::get('C_P_ACCEPT_BACKGROUND_COLOR'),
+ 'C_P_ACCEPT_BORDER_COLOR' => Configuration::get('C_P_ACCEPT_BORDER_COLOR'),
+ 'C_P_ACCEPT_FONT_COLOR' => Configuration::get('C_P_ACCEPT_FONT_COLOR'),
+ 'C_P_ACCEPT_FONT_SIZE' => Configuration::get('C_P_ACCEPT_FONT_SIZE'),
+ 'C_P_ACCEPT_PADDING' => Configuration::get('C_P_ACCEPT_PADDING'),
+ 'C_P_MORE_INFO_DISPLAY' => Configuration::get('C_P_MORE_INFO_DISPLAY'),
+ 'C_P_MORE_INFO_BACKGROUND_COLOR' => Configuration::get('C_P_MORE_INFO_BACKGROUND_COLOR'),
+ 'C_P_MORE_INFO_BORDER_COLOR' => Configuration::get('C_P_MORE_INFO_BORDER_COLOR'),
+ 'C_P_MORE_INFO_FONT_COLOR' => Configuration::get('C_P_MORE_INFO_FONT_COLOR'),
+ 'C_P_MORE_INFO_FONT_SIZE' => Configuration::get('C_P_MORE_INFO_FONT_SIZE'),
+ 'C_P_MORE_INFO_PADDING' => Configuration::get('C_P_MORE_INFO_PADDING'),
+ 'C_P_REJECT_DISPLAY' => Configuration::get('C_P_REJECT_DISPLAY'),
+ 'C_P_REJECT_BACKGROUND_COLOR' => Configuration::get('C_P_REJECT_BACKGROUND_COLOR'),
+ 'C_P_REJECT_BORDER_COLOR' => Configuration::get('C_P_REJECT_BORDER_COLOR'),
+ 'C_P_REJECT_FONT_COLOR' => Configuration::get('C_P_REJECT_FONT_COLOR'),
+ 'C_P_REJECT_FONT_SIZE' => Configuration::get('C_P_REJECT_FONT_SIZE'),
+ 'C_P_REJECT_PADDING' => Configuration::get('C_P_REJECT_PADDING'),
+ 'C_P_SAVE_BACKGROUND_COLOR' => Configuration::get('C_P_SAVE_BACKGROUND_COLOR'),
+ 'C_P_SAVE_BORDER_COLOR' => Configuration::get('C_P_SAVE_BORDER_COLOR'),
+ 'C_P_SAVE_FONT_COLOR' => Configuration::get('C_P_SAVE_FONT_COLOR'),
+ 'C_P_SAVE_FONT_SIZE' => Configuration::get('C_P_SAVE_FONT_SIZE'),
+ 'C_P_SAVE_PADDING' => Configuration::get('C_P_SAVE_PADDING'),
+ 'C_P_MATERIAL_ICONS_LIBRARY' => Configuration::get('C_P_MATERIAL_ICONS_LIBRARY'),
+ 'C_P_FINALITIES' => $cookiesPlusFinalities,
+ 'C_P_ICONS' => Configuration::get('C_P_ICONS'),
+ 'C_P_TAB_ENABLED' => Configuration::get('C_P_TAB_ENABLED'),
+ 'C_P_TAB_POSITION' => Configuration::get('C_P_TAB_POSITION'),
+ 'C_P_TAB_BACKGROUND_COLOR' => Configuration::get('C_P_TAB_BACKGROUND_COLOR'),
+ 'C_P_TAB_FONT_COLOR' => Configuration::get('C_P_TAB_FONT_COLOR'),
+ 'C_P_SAVE_CONSENT' => (int) Configuration::get('C_P_SAVE_CONSENT'),
+ 'C_P_CONSENT_HASH' => (Configuration::get('C_P_SAVE_CONSENT') && isset($cookiesPlusPreferences['consent_hash'])) ? $cookiesPlusPreferences['consent_hash'] : '',
+ 'C_P_CONSENT_DATE' => isset($cookiesPlusPreferences['consent_date']) ? $cookiesPlusPreferences['consent_date'] : '',
+ 'C_P_REVOKE_CONSENT' => Tools::displayDate(date('Y-m-d', strtotime(Configuration::get('C_P_REVOKE_CONSENT'))), null, false),
+ 'C_P_DISPLAY_DATE' => Configuration::get('C_P_DISPLAY_DATE'),
+ 'C_P_DEFAULT_CONSENT' => Configuration::get('C_P_DEFAULT_CONSENT'),
+ 'download_link' => isset($cookiesPlusPreferences['consent_hash']) ? $this->context->link->getModuleLink('cookiesplus', 'front') . '?hash=' . $cookiesPlusPreferences['consent_hash'] . '&getPdf' : '',
+ ]);
+
+ $html .= $this->display(__FILE__, 'cookies-notice.tpl');
+
+ return $html;
+ }
+
+ public function hookDisplayMobileHeader()
+ {
+ return $this->hookDisplayHeader();
+ }
+
+ public function hookDisplayFooterLinks()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayBeforeBodyClosingTag()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookTmMegaLayoutFooter()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookBlockFooter1()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayFooterBefore()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayFooterAfter()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplaySidebar()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayFooterNovOne()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayFooterNovTwo()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayBanner()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayCookies()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayMyAccountBlock()
+ {
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (!self::getGeo()) {
+ return;
+ }
+
+ if (version_compare(_PS_VERSION_, '1.7', '>=')) {
+ return $this->hookDisplayMyAccountBlockFooter();
+ }
+ }
+
+ public function hookDisplayMyAccountBlockFooter()
+ {
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (!self::getGeo()) {
+ return;
+ }
+
+ if (Configuration::get('C_P_ENABLE')) {
+ if (version_compare(_PS_VERSION_, '1.6', '<')) {
+ return $this->display(__FILE__, 'my-account-block-footer-15.tpl');
+ }
+
+ return $this->context->smarty->fetch($this->local_path . 'views/templates/hook/my-account-block-footer-17.tpl');
+ }
+ }
+
+ public function hookDisplayCustomerAccount()
+ {
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (!self::getGeo()) {
+ return;
+ }
+
+ if (Configuration::get('C_P_ENABLE')) {
+ if (version_compare(_PS_VERSION_, '1.6', '<')) {
+ return $this->display(__FILE__, 'customer_account_15.tpl');
+ }
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ return $this->display(__FILE__, 'customer_account_16.tpl');
+ }
+
+ $this->context->smarty->assign([
+ 'C_P_MATERIAL_ICONS_LIBRARY' => Configuration::get('C_P_MATERIAL_ICONS_LIBRARY'),
+ ]);
+
+ return $this->display(__FILE__, 'customer_account_17.tpl');
+ }
+
+ return false;
+ }
+
+ public function hookDisplayNav()
+ {
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (!self::getGeo()) {
+ return;
+ }
+
+ if (Configuration::get('C_P_ENABLE')) {
+ if (version_compare(_PS_VERSION_, '1.6', '<')) {
+ return $this->display(__FILE__, 'nav_16.tpl');
+ }
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ return $this->display(__FILE__, 'nav_16.tpl');
+ }
+
+ return $this->display(__FILE__, 'nav_17.tpl');
+ }
+
+ return false;
+ }
+
+ public function hookDisplayNav2()
+ {
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (!self::getGeo()) {
+ return;
+ }
+
+ return $this->hookDisplayNav();
+ }
+
+ public function hookDisplayTop()
+ {
+ return $this->hookFooter();
+ }
+
+ public function hookDisplayBackOfficeHeader()
+ {
+ if (version_compare(_PS_VERSION_, '1.7', '<')
+ && method_exists($this->context->controller, 'addCSS')) {
+ $this->context->controller->addCSS($this->_path . 'views/css/menuTabIcon.css');
+ }
+
+ // Remove expired CookiesPlusUserConsent
+ $expiredCookiesPlusUserConsents = CookiesPlusUserConsent::getCookiesPlusUserConsentExpired($this->context->shop->id);
+ foreach ($expiredCookiesPlusUserConsents as $expiredCookiesPlusUserConsent) {
+ $expiredCookiesPlusUserConsent = new CookiesPlusUserConsent((int) $expiredCookiesPlusUserConsent['id_cookiesplus_user_consent']);
+ $expiredCookiesPlusUserConsent->delete();
+ }
+ }
+
+ public function hookActionHtaccessCreate()
+ {
+ $path = _PS_ROOT_DIR_ . '/.htaccess';
+
+ $specific_before = $specific_after = '';
+ if (file_exists($path)) {
+ $content = Tools::file_get_contents($path);
+ if (preg_match('#^(.*)\# ~~startcookiesplus~~.*\# ~~endcookiesplus~~[^\n]*(.*)$#s', $content, $m)) {
+ $specific_before = $m[1];
+ $specific_after = $m[2];
+ } else {
+ $specific_before = $content;
+ }
+ }
+
+ // Write .htaccess data
+ if (!$write_fd = @fopen($path, 'w')) {
+ return false;
+ }
+
+ if (method_exists('Module', 'resetStaticCache')) {
+ Module::resetStaticCache();
+ }
+
+ if (self::isEnabled($this->name)) {
+ // https://www.imd.guru/sistemas/html/evitar_que_enlacen_directamente_a_imagenes_en_tu_web-Hotlinking.html
+ fwrite($write_fd, "# ~~startcookiesplus~~ Cookies Plus module - Do not remove this comment\n");
+ fwrite($write_fd, "\n");
+ fwrite($write_fd, "RewriteRule .* - [E=Cache-Vary:cookiesplus]\n");
+ fwrite($write_fd, "\n");
+ fwrite($write_fd, "# ~~endcookiesplus~~ Cookies Plus module - Do not remove this comment\n\n");
+ }
+
+ if ($specific_before) {
+ fwrite($write_fd, trim($specific_before) . "\n\n");
+ }
+
+ if ($specific_after) {
+ fwrite($write_fd, "\n\n" . trim($specific_after));
+ }
+
+ fclose($write_fd);
+
+ return true;
+ }
+
+ /**
+ * empty listener for registerGDPRConsent hook
+ */
+ public function hookRegisterGDPRConsent()
+ {
+ /* registerGDPRConsent is a special kind of hook that doesn't need a listener, see :
+ https://build.prestashop.com/howtos/module/how-to-make-your-module-compliant-with-prestashop-official-gdpr-compliance-module/
+ However since Prestashop 1.7.8, modules must implement a listener for all the hooks they register: a check is made
+ at module installation.
+ */
+ }
+
+ public function hookActionShopDataDuplication($params)
+ {
+ $cookiesPlusCookies = Db::getInstance()->executeS(
+ 'SELECT * FROM ' . _DB_PREFIX_ . 'cookiesplus_cookie
+ WHERE id_shop = ' . (int) $params['old_id_shop']
+ );
+
+ foreach ($cookiesPlusCookies as $id => $cookiesPlusCookie) {
+ Db::getInstance()->execute('
+ INSERT IGNORE INTO ' . _DB_PREFIX_ . 'cookiesplus_cookie (id_cookiesplus_cookie, id_shop, active, id_cookiesplus_finality, name, provider, provider_url, date_add, date_upd)
+ VALUES (null, ' . (int) $params['new_id_shop'] . ', ' . (int) $cookiesPlusCookie['active'] . ', ' . (int) $cookiesPlusCookie['id_cookiesplus_finality'] . ', \'' . pSQL($cookiesPlusCookie['name']) . '\', \'' . pSQL($cookiesPlusCookie['provider']) . '\', \'' . pSQL($cookiesPlusCookie['provider_url']) . '\', \'' . date('Y-m-d H:i:s') . '\', \'' . date('Y-m-d H:i:s') . '\')');
+
+ $cookiesPlusCookies[$id]['new_id_cookiesplus_cookie'] = Db::getInstance()->Insert_ID();
+ }
+
+ foreach ($cookiesPlusCookies as $cookiesPlusCookie) {
+ $languages = Db::getInstance()->executeS('
+ SELECT id_lang, purpose, expiry
+ FROM ' . _DB_PREFIX_ . 'cookiesplus_cookie_lang
+ WHERE id_cookiesplus_cookie = ' . (int) $cookiesPlusCookie['id_cookiesplus_cookie']);
+
+ foreach ($languages as $language) {
+ Db::getInstance()->execute('
+ INSERT IGNORE INTO ' . _DB_PREFIX_ . 'cookiesplus_cookie_lang (id_cookiesplus_cookie, id_lang, purpose, expiry)
+ VALUES (' . (int) $cookiesPlusCookie['new_id_cookiesplus_cookie'] . ', ' . (int) $language['id_lang'] . ', \'' . pSQL($language['purpose']) . '\', \'' . pSQL($language['expiry']) . '\')');
+ }
+ }
+
+ $cookiesPlusFinalities = Db::getInstance()->executeS(
+ 'SELECT * FROM ' . _DB_PREFIX_ . 'cookiesplus_finality
+ WHERE id_shop = ' . (int) $params['old_id_shop']
+ );
+
+ foreach ($cookiesPlusFinalities as $id => $cookiesPlusFinality) {
+ Db::getInstance()->execute('
+ INSERT IGNORE INTO ' . _DB_PREFIX_ . 'cookiesplus_finality (id_cookiesplus_finality, id_shop, active, technical, modules, js_script, js_not_script, position, date_add, date_upd)
+ VALUES (null, ' . (int) $params['new_id_shop'] . ', ' . (int) $cookiesPlusFinality['active'] . ', ' . (int) $cookiesPlusFinality['technical'] . ', \'' . pSQL($cookiesPlusFinality['modules']) . '\', \'' . pSQL($cookiesPlusFinality['js_script']) . '\', \'' . pSQL($cookiesPlusFinality['js_not_script']) . '\', ' . (int) $cookiesPlusFinality['position'] . ', \'' . date('Y-m-d H:i:s') . '\', \'' . date('Y-m-d H:i:s') . '\')');
+
+ $cookiesPlusFinalities[$id]['new_id_cookiesplus_finality'] = Db::getInstance()->Insert_ID();
+ }
+
+ foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ $languages = Db::getInstance()->executeS('
+ SELECT id_lang, name, description
+ FROM ' . _DB_PREFIX_ . 'cookiesplus_finality_lang
+ WHERE id_cookiesplus_finality = ' . (int) $cookiesPlusFinality['id_cookiesplus_finality']);
+
+ foreach ($languages as $language) {
+ Db::getInstance()->execute('
+ INSERT IGNORE INTO ' . _DB_PREFIX_ . 'cookiesplus_finality_lang (id_cookiesplus_finality, id_lang, name, description)
+ VALUES (' . (int) $cookiesPlusFinality['new_id_cookiesplus_finality'] . ', ' . (int) $language['id_lang'] . ', \'' . pSQL($language['name']) . '\', \'' . pSQL($language['description']) . '\')');
+ }
+ }
+ }
+
+ public function hookActionOutputHTMLBefore($params)
+ {
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (Configuration::get('C_P_FB_ENABLE')) {
+ $cookiesPlusCookiePreferences = self::getCookiesPlusCookiePreferences();
+ $fbConsents = json_decode(Configuration::get('C_P_FB_CONSENT'), true) ?: [];
+ $fbAllConsent = true;
+ foreach (array_keys($fbConsents) as $fbConsent) {
+ $key = 'cookiesplus-finality-' . (int) $fbConsent;
+ if (!isset($cookiesPlusCookiePreferences[$key])
+ || $cookiesPlusCookiePreferences[$key] !== 'on') {
+ $fbAllConsent = false;
+ break;
+ }
+ }
+
+ $position = strpos($params['html'], "fbq('init'");
+
+ if ($position) {
+ if ($fbAllConsent) {
+ $params['html'] = substr_replace($params['html'], "fbq('consent', 'grant');", $position, 0);
+ } else {
+ $params['html'] = substr_replace($params['html'], "fbq('consent', 'revoke');", $position, 0);
+ }
+ }
+ }
+
+ if (Configuration::get('C_P_YT_ENABLE')) {
+ $cookiesPlusCookiePreferences = self::getCookiesPlusCookiePreferences();
+ $ytConsents = json_decode(Configuration::get('C_P_YT_CONSENT'), true) ?: [];
+ $ytAllConsent = true;
+ foreach (array_keys($ytConsents) as $ytConsents) {
+ $key = 'cookiesplus-finality-' . (int) $ytConsents;
+ if (!isset($cookiesPlusCookiePreferences[$key])
+ || $cookiesPlusCookiePreferences[$key] !== 'on') {
+ $ytAllConsent = false;
+ break;
+ }
+ }
+
+ if (!$ytAllConsent) {
+ $params['html'] = str_replace('youtube.com/embed/', 'youtube-nocookie.com/embed/', $params['html']);
+ // Elementor
+ $params['html'] = str_replace('data-video-id=', 'data-video-id-blocked=', $params['html']);
+ }
+ }
+ }
+
+ /* Module functions */
+ /* Backward compatibility */
+ public static function updateCookie($modules)
+ {
+ return self::filterHookModuleExecList($modules);
+ }
+
+ public static function filterHookModuleExecList($modules, $hook_name = null)
+ {
+ // return $modules;
+ if (!self::executeModule()) {
+ return $modules;
+ }
+
+ if (!self::getGeo()) {
+ return $modules;
+ }
+
+ // Exclude admin calls
+ /*
+ if (defined('_PS_ADMIN_DIR_')) {
+ return $modules;
+ }
+ */
+ if (is_object(Context::getContext()->controller)
+ && isset(Context::getContext()->controller->controller_type)
+ && Context::getContext()->controller->controller_type === 'admin') {
+ return $modules;
+ }
+
+ // Exclude .map extensions
+ $url = parse_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+ if (isset($url['path']) && pathinfo($url['path'], PATHINFO_EXTENSION) === 'map') {
+ return $modules;
+ }
+ $url = parse_url("https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+ if (isset($url['path']) && pathinfo($url['path'], PATHINFO_EXTENSION) === 'map') {
+ return $modules;
+ }
+
+ $cookiesPlusPreferences = self::getCookiesPlusCookiePreferences();
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities(null, true);
+
+ foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ if (!$cookiesPlusFinality['technical']
+ && (!isset($cookiesPlusPreferences['cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']])
+ || (isset($cookiesPlusPreferences['cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']])
+ && $cookiesPlusPreferences['cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']] !== 'on'))) {
+ $blockedModulesId = json_decode($cookiesPlusFinality['modules'], true) ?: [];
+
+ if (is_array($modules) && is_array($blockedModulesId)) {
+ foreach ($modules as $key => $module) {
+ // Cookiesplus module can not be blocked
+ if ($module['module'] === 'cookiesplus') {
+ continue;
+ }
+
+ if (in_array($module['id_module'], $blockedModulesId)) {
+ unset($modules[$key]);
+ }
+ }
+ }
+ }
+ }
+
+ return $modules;
+ }
+
+ public function blockModuleCode($params)
+ {
+ // Recursive call
+ if (!self::executeModule()) {
+ return;
+ }
+
+ if (!self::getGeo()) {
+ return;
+ }
+
+ // Exclude admin calls
+ /*
+ if (defined('_PS_ADMIN_DIR_')) {
+ return $modules;
+ }
+ */
+ $context = Context::getContext();
+
+ if (!$context->controller) {
+ return;
+ }
+
+ if (is_object($context->controller)
+ && isset($context->controller->controller_type)
+ && ($context->controller->controller_type === 'admin'
+ || $context->controller->controller_type === 'moduleadmin')) {
+ return;
+ }
+
+ // Exclude .map extensions
+ $url = parse_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+ if (isset($url['path']) && pathinfo($url['path'], PATHINFO_EXTENSION) === 'map') {
+ return;
+ }
+ $url = parse_url("https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+ if (isset($url['path']) && pathinfo($url['path'], PATHINFO_EXTENSION) === 'map') {
+ return;
+ }
+
+ $blockedModulesByFinality = self::getBlockedModulesByFinality();
+
+ if (version_compare(_PS_VERSION_, '1.6.1', '>=')) {
+ return $this->blockModuleCode17($params, $context, $blockedModulesByFinality);
+ }
+
+ return $this->blockModuleCode15($params, $context, $blockedModulesByFinality);
+ }
+
+ public function getBlockedModulesByFinality()
+ {
+ $cacheKey = 'CookiesPlus::blockModuleCode';
+
+ if (!Cache::isStored($cacheKey)) {
+ $cookiesPlusPreferences = self::getCookiesPlusCookiePreferences();
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities(null, true);
+
+ $blockedModulesByFinality = [];
+ foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ $index = 'cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality'];
+ if (!$cookiesPlusFinality['technical']
+ && (!isset($cookiesPlusPreferences[$index])
+ || (isset($cookiesPlusPreferences[$index])
+ && $cookiesPlusPreferences[$index] !== 'on'))
+ ) {
+ $blockedModulesId = json_decode($cookiesPlusFinality['modules'], true) ?: [];
+
+ if (is_array($blockedModulesId)) {
+ foreach ($blockedModulesId as $module) {
+ // Cookiesplus module can not be blocked
+ if ($module === $this->id) {
+ continue;
+ }
+
+ $blockedModulesByFinality[(int) $module]['finalities'][] = (int) $cookiesPlusFinality['id_cookiesplus_finality'];
+ }
+ }
+ }
+ }
+
+ Cache::store($cacheKey, $blockedModulesByFinality);
+ }
+
+ return Cache::retrieve($cacheKey);
+ }
+
+ public function blockModuleCode17($params, $context, $blockedModulesByFinality)
+ {
+ if (isset($blockedModulesByFinality[$params['module']->id])) {
+ // Remove JS and CSS files from blocked modules
+ $js_files = [];
+ $css_files = [];
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ $jsFileList = $context->controller->js_files;
+ foreach ($jsFileList as $jsFile) {
+ if (strpos($jsFile, '/modules/' . $params['module']->name) !== false) {
+ $js_files[] = $jsFile;
+ $context->controller->removeJs($jsFile);
+ }
+ }
+
+ $cssFileList = $context->controller->css_files;
+ foreach ($cssFileList as $cssFile) {
+ if (strpos($cssFile, '/modules/' . $params['module']->name) !== false) {
+ $css_files[] = $cssFile;
+ $context->controller->removeJs($cssFile);
+ }
+ }
+ } else {
+ $jsFileList = $context->controller->getJavascript();
+ foreach ($jsFileList as $jsFileListPart) {
+ foreach ($jsFileListPart as $jsFileListPartContainer) {
+ foreach ($jsFileListPartContainer as $jsFileListPartContainerFile) {
+ if (strpos($jsFileListPartContainerFile['path'], '/modules/' . $params['module']->name) !== false) {
+ $js_files[] = $jsFileListPartContainerFile['path'];
+ $context->controller->removeJs($jsFileListPartContainerFile['path']);
+ $context->controller->unregisterJavascript($jsFileListPartContainerFile['id']);
+ }
+ }
+ }
+ }
+
+ $cssFileList = $context->controller->getStylesheets();
+ foreach ($cssFileList as $cssFileListPartContainer) {
+ foreach ($cssFileListPartContainer as $cssFileListPartContainerFile) {
+ if (strpos($cssFileListPartContainerFile['path'], '/modules/' . $params['module']->name) !== false) {
+ $css_files[] = $cssFileListPartContainerFile['path'];
+ $context->controller->removeCSS($cssFileListPartContainerFile['path']);
+ $context->controller->unregisterStylesheet($jsFileListPartContainerFile['id']);
+ }
+ }
+ }
+ }
+
+ // Remove cookies
+ if (isset($params['headersBeforeExecution']) && $params['headersBeforeExecution']) {
+ // Remove the original headers
+ header_remove();
+
+ // Set old headers
+ foreach ($params['headersBeforeExecution'] as $header) {
+ header($header, false);
+ }
+ }
+
+ if (Configuration::get('C_P_REFRESH')) {
+ // The module is blocked but with refresh. Don't display any content
+ $params['display'] = '';
+ } else {
+ if ($params['display']) {
+ $originalReturn = $params['display'];
+ $random = Tools::substr(md5(microtime()), 0, 10);
+ $divName = $params['hookName'] . '_' . $params['module']->id . '_' . $random;
+
+ $this->context->smarty->assign([
+ 'divName' => $divName,
+ 'id_module' => $params['module']->id,
+ 'finalities' => implode(',', $blockedModulesByFinality[$params['module']->id]['finalities']),
+ 'script' => json_encode($originalReturn),
+ 'js' => empty($js_files) ? '[]' : json_encode($js_files),
+ 'css' => empty($css_files) ? '[]' : json_encode($css_files),
+ ]);
+
+ $params['display'] = $this->context->smarty->fetch($this->local_path . 'views/templates/hook/hookmoduledata.tpl');
+ }
+ }
+ }
+ }
+
+ public function blockModuleCode15($params, $context, $blockedModulesByFinality)
+ {
+ if (!is_array($params['return'])) {
+ return;
+ }
+
+ foreach (array_keys($params['return']) as $module) {
+ $module = Module::getInstanceByName($module);
+ if (isset($blockedModulesByFinality[$module->id])) {
+ // Remove JS and CSS files from blocked modules
+ $js_files = [];
+ $css_files = [];
+
+ if (version_compare(_PS_VERSION_, '1.7', '<')) {
+ $jsFileList = $context->controller->js_files;
+ foreach ($jsFileList as $jsFile) {
+ if (strpos($jsFile, '/modules/' . $module->name) !== false) {
+ $js_files[] = $jsFile;
+ $context->controller->removeJs($jsFile);
+ }
+ }
+
+ $cssFileList = $context->controller->css_files;
+ foreach ($cssFileList as $cssFile) {
+ if (strpos($cssFile, '/modules/' . $module->name) !== false) {
+ $css_files[] = $cssFile;
+ $context->controller->removeJs($cssFile);
+ }
+ }
+ } else {
+ $jsFileList = $context->controller->getJavascript();
+ foreach ($jsFileList as $jsFileListPart) {
+ foreach ($jsFileListPart as $jsFileListPartContainer) {
+ foreach ($jsFileListPartContainer as $jsFileListPartContainerFile) {
+ if (strpos($jsFileListPartContainerFile['path'], '/modules/' . $module->name) !== false) {
+ $js_files[] = $jsFileListPartContainerFile['path'];
+ $context->controller->removeJs($jsFileListPartContainerFile['path']);
+ }
+ }
+ }
+ }
+
+ $cssFileList = $context->controller->getStylesheets();
+ foreach ($cssFileList as $cssFileListPartContainer) {
+ foreach ($cssFileListPartContainer as $cssFileListPartContainerFile) {
+ if (strpos($cssFileListPartContainerFile['path'], '/modules/' . $module->name) !== false) {
+ $css_files[] = $cssFileListPartContainerFile['path'];
+ $context->controller->removeCSS($cssFileListPartContainerFile['path']);
+ }
+ }
+ }
+ }
+
+ if (Configuration::get('C_P_REFRESH')) {
+ $params['return'][$module->name] = '';
+ } else {
+ $originalReturn = $params['return'][$module->name];
+ $random = Tools::substr(md5(microtime()), 0, 10);
+ $divName = $params['hookName'] . '_' . $module->id . '_' . $random;
+
+ $this->context->smarty->assign([
+ 'divName' => $divName,
+ 'id_module' => $module->id,
+ 'finalities' => implode(',', $blockedModulesByFinality[$module->id]['finalities']),
+ 'script' => json_encode($originalReturn),
+ 'js' => empty($js_files) ? '[]' : json_encode($js_files),
+ 'css' => empty($css_files) ? '[]' : json_encode($css_files),
+ ]);
+
+ $params['return'][$module->name] = $this->context->smarty->fetch($this->local_path . 'views/templates/hook/hookmoduledata.tpl');
+ }
+ }
+ }
+ }
+
+ public function blockModuleCache($modulesToInvoke, $hookName)
+ {
+ if (empty($modulesToInvoke)) {
+ return false;
+ }
+
+ // Don't filter in BO
+ $context = Context::getContext();
+ if (isset($context->controller->controller_type) && $context->controller->controller_type === 'admin') {
+ return $modulesToInvoke;
+ }
+
+ if (!Configuration::get('C_P_REFRESH')) {
+ return $modulesToInvoke;
+ }
+
+ $cookiesPlusPreferences = self::getCookiesPlusCookiePreferences();
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities(null, true);
+
+ $blockedModulesByFinality = [];
+ foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ $index = 'cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality'];
+ if (!$cookiesPlusFinality['technical']
+ && (!isset($cookiesPlusPreferences[$index])
+ || (isset($cookiesPlusPreferences[$index])
+ && $cookiesPlusPreferences[$index] !== 'on'))
+ ) {
+ $blockedModulesId = json_decode($cookiesPlusFinality['modules'], true) ?: [];
+
+ if (is_array($blockedModulesId)) {
+ foreach ($blockedModulesId as $module) {
+ // Cookiesplus module can not be blocked
+ if ($module === $this->id) {
+ continue;
+ }
+
+ $blockedModulesByFinality[(int) $module]['finalities'][] = (int) $cookiesPlusFinality['id_cookiesplus_finality'];
+ }
+ }
+ }
+ }
+
+ if (null === $hookName) {
+ foreach ($modulesToInvoke as $modulesToInvokeByHook) {
+ foreach ($modulesToInvokeByHook as $moduleToInvokeKey => $moduleToInvoke) {
+ if (in_array($moduleToInvoke['id_module'], array_keys($blockedModulesByFinality))) {
+ unset($modulesToInvoke[$moduleToInvokeKey]);
+ }
+ }
+ }
+ } else {
+ foreach ($modulesToInvoke as $moduleToInvokeKey => $moduleToInvoke) {
+ if (in_array($moduleToInvoke['id_module'], array_keys($blockedModulesByFinality))) {
+ unset($modulesToInvoke[$moduleToInvokeKey]);
+ }
+ }
+ }
+
+ return $modulesToInvoke;
+ }
+
+ public function resetCookiesPlusPreferences()
+ {
+ $cookieExpiryTime = time() + Configuration::get('C_P_EXPIRY') * 86400;
+
+ $result = setcookie('cookiesplus', json_encode([]), $cookieExpiryTime, '/');
+
+ return true;
+ }
+
+ public function saveCookiesPlusPreferences()
+ {
+ // $cookiesPlusFinalityValue = self::getCookiesPlusCookiePreferences();
+
+ $cookiesPlusFinalityValue = [];
+ // $cookiesPlusFinalityValue['C_P_DISPLAY_MODAL'] = false;
+
+ if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
+ $ip = $_SERVER['HTTP_CLIENT_IP'];
+ } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ } else {
+ $ip = $_SERVER['REMOTE_ADDR'];
+ }
+
+ /*foreach ($cookiesPlusFinalities as $cookiesPlusFinality) {
+ $cookiesPlusFinalityValue['cookiesplus-finality-' . (int)$cookiesPlusFinality['id_cookiesplus_finality']] = Tools::getValue('cookiesplus-finality-' . (int)$cookiesPlusFinality['id_cookiesplus_finality']);
+ }*/
+ // $cookieExpiryTime = time() + Configuration::get('C_P_EXPIRY') * 86400;
+ // $cookiesPlusFinalityValue['expiry'] = time() + Configuration::get('C_P_EXPIRY') * 86400;
+ // $cookiesPlusFinalityValue['consent_date'] = date('Y-m-d H:i:s', time());
+ // $result = setcookie('cookiesplus', json_encode($cookiesPlusFinalityValue), $cookieExpiryTime, '/');
+
+ // $cookiesPlusFinalityValue['cookie'] = json_encode($cookiesPlusFinalityValue);
+
+ // Generate PDF consent
+ if (Configuration::get('C_P_SAVE_CONSENT')) {
+ do {
+ $consentHash = md5(openssl_random_pseudo_bytes(20)) . '-' . Tools::substr(md5(openssl_random_pseudo_bytes(20)), 0, 8);
+ } while (!$consentHash);
+ $cookiesPlusFinalityValue['consent_hash'] = $consentHash;
+ $consentDate = date('Y-m-d H:i', time());
+
+ $data = [];
+ $data['cookiesPlus']['info']['last_update'] = Tools::displayDate(date('Y-m-d', strtotime(Configuration::get('C_P_REVOKE_CONSENT'))), null, false);
+ $data['cookiesPlus']['info']['consent_hash'] = $cookiesPlusFinalityValue['consent_hash'];
+ $data['cookiesPlus']['info']['consent_date'] = $consentDate;
+ $data['cookiesPlus']['info']['consent_ip'] = $ip;
+
+ $cookiesPlusFinalities = CookiesPlusFinality::getCookiesPlusFinalities((int) $this->context->language->id, true);
+ foreach ($cookiesPlusFinalities as &$cookiesPlusFinality) {
+ $cookiesPlusFinality['cookies'] = CookiesPlusCookie::getCookiesPlusCookies($cookiesPlusFinality['id_cookiesplus_finality'], (int) $this->context->language->id, true, $this->context->shop->id);
+ if (Tools::getValue('cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']) !== 'na'
+ && Tools::getValue('cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']) !== 'on'
+ && Tools::getValue('cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']) !== 'off'
+ ) {
+ $_POST['cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']] = 'na';
+ }
+ $cookiesPlusFinality['cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']] = Tools::getValue('cookiesplus-finality-' . (int) $cookiesPlusFinality['id_cookiesplus_finality']);
+ }
+ unset($cookiesPlusFinality);
+ $data['cookiesPlus']['cookiesPlusFinalities'] = $cookiesPlusFinalities;
+
+ // Send an email to admin because of an error
+ /*if (!$result) {
+ Configuration::updateValue('C_P_SAVE_CONSENT', 0);
+ }*/
+ // Save consent
+ $cookiesPlusUserConsent = new CookiesPlusUserConsent();
+ $cookiesPlusUserConsent->data = json_encode($data);
+ $cookiesPlusUserConsent->hash = $cookiesPlusFinalityValue['consent_hash'];
+ $cookiesPlusUserConsent->date = $consentDate;
+ $cookiesPlusUserConsent->ip = $ip;
+ $cookiesPlusUserConsent->save();
+ }
+
+ return $cookiesPlusFinalityValue;
+ }
+
+ public static function getCookiesPlusCookiePreferences()
+ {
+ if (isset($_COOKIE['cookiesplus'])) {
+ return json_decode($_COOKIE['cookiesplus'], true);
+ }
+
+ return [];
+ }
+
+ public static function isCookiesPlusFinalityAccepted($id_cookiesplus_finality)
+ {
+ $cookiesPlusCookiePreferences = self::getCookiesPlusCookiePreferences();
+
+ $index = 'cookiesplus-finality-' . (int) $id_cookiesplus_finality;
+
+ if (isset($cookiesPlusCookiePreferences[$index])
+ && $cookiesPlusCookiePreferences[$index] === 'on') {
+ return true;
+ }
+
+ return false;
+ }
+
+ public function copyOverrideFolder()
+ {
+ if (Module::isInstalled('pagecache')) {
+ return true;
+ }
+
+ if (!is_writable(_PS_MODULE_DIR_ . $this->name)) {
+ return false;
+ }
+
+ $override_folder_name = 'override';
+ if (version_compare(_PS_VERSION_, '1.6.1', '>=')) {
+ $psVersion = '17';
+ } elseif (version_compare(_PS_VERSION_, '1.6', '>=')) {
+ $psVersion = '16';
+ } else {
+ $psVersion = '15';
+ }
+
+ $version_override_folder = _PS_MODULE_DIR_ . $this->name . '/' . $override_folder_name . '_' . $psVersion;
+ $override_folder = _PS_MODULE_DIR_ . $this->name . '/' . $override_folder_name;
+
+ if (file_exists($override_folder) && is_dir($override_folder)) {
+ $this->recursiveRmdir($override_folder);
+ }
+
+ if (is_dir($version_override_folder)) {
+ $this->copyDir($version_override_folder, $override_folder);
+ }
+
+ return true;
+ }
+
+ public function copyDir($src, $dst)
+ {
+ if (is_dir($src)) {
+ $dir = opendir($src);
+ if (!mkdir($dst) && !is_dir($dst)) {
+ throw new RuntimeException(sprintf('Directory "%s" was not created', $dst));
+ }
+ while (false !== ($file = readdir($dir))) {
+ if (($file !== '.') && ($file !== '..')) {
+ if (is_dir($src . '/' . $file)) {
+ $this->copyDir($src . '/' . $file, $dst . '/' . $file);
+ } else {
+ copy($src . '/' . $file, $dst . '/' . $file);
+ }
+ }
+ }
+ closedir($dir);
+ }
+ }
+
+ public function recursiveRmdir($dir)
+ {
+ if (is_dir($dir)) {
+ $objects = scandir($dir);
+ foreach ($objects as $object) {
+ if ($object !== '.' && $object !== '..') {
+ if (filetype($dir . '/' . $object) === 'dir') {
+ $this->recursiveRmdir($dir . '/' . $object);
+ } else {
+ unlink($dir . '/' . $object);
+ }
+ }
+ }
+ reset($objects);
+ rmdir($dir);
+ }
+ }
+
+ public static function sanitizeJson($json)
+ {
+ $escapers = ['\\', '/', '"', "\n", "\r", "\t", "\x08", "\x0c", "\'"];
+ $replacements = ['\\\\', '\\/', '\\"', '\\n', '\\r', '\\t', '\\f', '\\b', "\\\'"];
+
+ return str_replace($escapers, $replacements, $json);
+ }
+
+ public function getDatabaseVersion()
+ {
+ $query = 'SELECT `version`
+ FROM `' . _DB_PREFIX_ . 'module`
+ WHERE `name` = \'' . $this->name . '\';';
+
+ return Db::getInstance()->getValue($query);
+ }
+}
diff --git a/modules/pp_carousel/config.xml b/modules/pp_carousel/config.xml
new file mode 100644
index 0000000..782b6c2
--- /dev/null
+++ b/modules/pp_carousel/config.xml
@@ -0,0 +1,12 @@
+
+
+ pp_carousel
+
+
+
+
+
+ 1
+ 0
+
+
diff --git a/modules/pp_carousel/index.php b/modules/pp_carousel/index.php
new file mode 100644
index 0000000..8e50318
--- /dev/null
+++ b/modules/pp_carousel/index.php
@@ -0,0 +1,16 @@
+
+ * @copyright Project-Pro
+ * @license https://www.project-pro.pl
+ */
+
+header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+header('Cache-Control: no-store, no-cache, must-revalidate');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache');
+header('Location: ../');
+exit;
diff --git a/modules/pp_carousel/pp_carousel.php b/modules/pp_carousel/pp_carousel.php
new file mode 100644
index 0000000..4ed4dbe
--- /dev/null
+++ b/modules/pp_carousel/pp_carousel.php
@@ -0,0 +1,762 @@
+name = 'pp_carousel';
+ $this->tab = 'front_office_features';
+ $this->version = '1.0.0';
+ $this->author = 'Project-Pro';
+ $this->author_uri = 'https://www.project-pro.pl';
+ $this->need_instance = 0;
+ $this->bootstrap = true;
+
+ parent::__construct();
+
+ $this->displayName = $this->l('Project-Pro Karuzela Produktów');
+ $this->description = $this->l('Wyświetla konfigurowalne karuzele produktów w dowolnych hookach.');
+ $this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
+ }
+
+ public function install()
+ {
+ return $this->executeSqlFile('install')
+ && parent::install()
+ && $this->registerHook('displayHeader')
+ && $this->registerHook('displayHome')
+ && $this->registerHook('displayFooterBefore')
+ && $this->registerHook('displayTopColumn')
+ && $this->registerHook('displayLeftColumn')
+ && $this->registerHook('displayRightColumn')
+ && $this->registerHook('displayFooter');
+ }
+
+ public function uninstall()
+ {
+ return $this->executeSqlFile('uninstall') && parent::uninstall();
+ }
+
+ private function executeSqlFile($filename)
+ {
+ $path = dirname(__FILE__) . '/sql/' . $filename . '.sql';
+ if (!file_exists($path)) {
+ return false;
+ }
+
+ $sql = file_get_contents($path);
+ $sql = str_replace('PREFIX_', _DB_PREFIX_, $sql);
+ $sql = str_replace('ENGINE_TYPE', _MYSQL_ENGINE_, $sql);
+
+ $queries = preg_split('/;\s*[\r\n]+/', $sql);
+ foreach ($queries as $query) {
+ $query = trim($query);
+ if (!empty($query)) {
+ if (!Db::getInstance()->execute($query)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // ─── ADMIN PANEL ────────────────────────────────────────────
+
+ public function getContent()
+ {
+ $output = '';
+
+ if (Tools::isSubmit('deletepp_carousel')) {
+ $output .= $this->deleteCarousel((int) Tools::getValue('id_carousel'));
+ }
+
+ if (Tools::isSubmit('statuspp_carousel')) {
+ $output .= $this->toggleCarouselStatus((int) Tools::getValue('id_carousel'));
+ }
+
+ if (Tools::isSubmit('submitPpCarousel')) {
+ $output .= $this->saveCarousel();
+ }
+
+ if (Tools::isSubmit('addpp_carousel') || Tools::isSubmit('updatepp_carousel') || Tools::getValue('id_carousel')) {
+ return $output . $this->renderForm((int) Tools::getValue('id_carousel'));
+ }
+
+ return $output . $this->renderList();
+ }
+
+ private function renderList()
+ {
+ $fieldsList = [
+ 'id_carousel' => ['title' => 'ID', 'align' => 'center', 'class' => 'fixed-width-xs'],
+ 'title' => ['title' => $this->l('Tytuł')],
+ 'hook_name' => ['title' => $this->l('Hook')],
+ 'source_type' => ['title' => $this->l('Źródło')],
+ 'limit_products' => ['title' => $this->l('Limit'), 'align' => 'center', 'class' => 'fixed-width-xs'],
+ 'active' => ['title' => $this->l('Aktywna'), 'active' => 'status', 'align' => 'center', 'class' => 'fixed-width-sm', 'type' => 'bool'],
+ ];
+
+ $helper = new HelperList();
+ $helper->shopLinkType = '';
+ $helper->simple_header = false;
+ $helper->actions = ['edit', 'delete'];
+ $helper->identifier = 'id_carousel';
+ $helper->show_toolbar = true;
+ $helper->title = $this->l('Karuzele produktów');
+ $helper->table = $this->name;
+ $helper->token = Tools::getAdminTokenLite('AdminModules');
+ $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
+
+ $helper->toolbar_btn['new'] = [
+ 'href' => AdminController::$currentIndex . '&configure=' . $this->name . '&add' . $this->name . '&token=' . Tools::getAdminTokenLite('AdminModules'),
+ 'desc' => $this->l('Dodaj karuzelę'),
+ ];
+
+ return $helper->generateList($this->getCarouselList(), $fieldsList);
+ }
+
+ private function getCarouselList()
+ {
+ $idLang = (int) $this->context->language->id;
+
+ $sql = 'SELECT c.*, cl.title
+ FROM `' . _DB_PREFIX_ . 'pp_carousel` c
+ LEFT JOIN `' . _DB_PREFIX_ . 'pp_carousel_lang` cl
+ ON c.id_carousel = cl.id_carousel AND cl.id_lang = ' . $idLang . '
+ WHERE c.id_shop = ' . (int) $this->context->shop->id . '
+ ORDER BY c.position ASC, c.id_carousel ASC';
+
+ return Db::getInstance()->executeS($sql) ?: [];
+ }
+
+ private function renderForm($idCarousel = 0)
+ {
+ $carousel = $idCarousel ? $this->getCarousel($idCarousel) : [];
+ $defaultLang = (int) Configuration::get('PS_LANG_DEFAULT');
+ $langs = Language::getLanguages(false);
+ $categories = $this->flattenCategories(Category::getCategories($defaultLang, true, false));
+
+ $hookOptions = $this->getAvailableHooks();
+
+ $sourceOptions = [
+ ['id' => 'new', 'name' => $this->l('Nowości')],
+ ['id' => 'bestseller', 'name' => $this->l('Bestsellery')],
+ ['id' => 'category', 'name' => $this->l('Produkty z kategorii')],
+ ['id' => 'manual', 'name' => $this->l('Ręczne ID produktów')],
+ ];
+
+ $fieldsForm = [
+ 'form' => [
+ 'legend' => [
+ 'title' => $idCarousel ? $this->l('Edytuj karuzelę') : $this->l('Dodaj karuzelę'),
+ 'icon' => 'icon-cogs',
+ ],
+ 'input' => [
+ [
+ 'type' => 'hidden',
+ 'name' => 'id_carousel',
+ ],
+ [
+ 'type' => 'select',
+ 'label' => $this->l('Hook (miejsce wyświetlania)'),
+ 'name' => 'hook_name',
+ 'options' => ['query' => $hookOptions, 'id' => 'id', 'name' => 'name'],
+ 'desc' => $this->l('Wybierz hook lub wpisz niestandardowy poniżej.'),
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Niestandardowy hook'),
+ 'name' => 'custom_hook',
+ 'desc' => $this->l('Jeśli wypełnione, zostanie użyte zamiast wybranego powyżej. Hook zostanie utworzony automatycznie.'),
+ ],
+ [
+ 'type' => 'select',
+ 'label' => $this->l('Źródło produktów'),
+ 'name' => 'source_type',
+ 'options' => ['query' => $sourceOptions, 'id' => 'id', 'name' => 'name'],
+ 'id' => 'source_type_select',
+ ],
+ [
+ 'type' => 'select',
+ 'label' => $this->l('Kategoria'),
+ 'name' => 'id_category',
+ 'options' => ['query' => $categories, 'id' => 'id', 'name' => 'name'],
+ 'desc' => $this->l('Widoczne gdy źródło = "Produkty z kategorii".'),
+ 'form_group_class' => 'pp-field-category',
+ ],
+ [
+ 'type' => 'textarea',
+ 'label' => $this->l('ID produktów (ręczne)'),
+ 'name' => 'product_ids',
+ 'desc' => $this->l('ID produktów rozdzielone przecinkami, np. 12,45,67. Widoczne gdy źródło = "Ręczne ID".'),
+ 'form_group_class' => 'pp-field-manual',
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Limit produktów'),
+ 'name' => 'limit_products',
+ 'class' => 'fixed-width-sm',
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Tytuł'),
+ 'name' => 'title',
+ 'lang' => true,
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Podtytuł'),
+ 'name' => 'subtitle',
+ 'lang' => true,
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Tekst przycisku'),
+ 'name' => 'button_label',
+ 'lang' => true,
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('URL przycisku'),
+ 'name' => 'button_url',
+ 'desc' => $this->l('Pozostaw puste, aby linkować do kategorii automatycznie.'),
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Sufiks ceny'),
+ 'name' => 'price_suffix',
+ 'lang' => true,
+ 'desc' => $this->l('Np. /m²'),
+ ],
+ [
+ 'type' => 'text',
+ 'label' => $this->l('Pozycja'),
+ 'name' => 'position',
+ 'class' => 'fixed-width-sm',
+ ],
+ [
+ 'type' => 'switch',
+ 'label' => $this->l('Aktywna'),
+ 'name' => 'active',
+ 'values' => [
+ ['id' => 'active_on', 'value' => 1, 'label' => $this->l('Tak')],
+ ['id' => 'active_off', 'value' => 0, 'label' => $this->l('Nie')],
+ ],
+ ],
+ ],
+ 'submit' => [
+ 'title' => $this->l('Zapisz'),
+ 'name' => 'submitPpCarousel',
+ ],
+ ],
+ ];
+
+ $helper = new HelperForm();
+ $helper->show_toolbar = false;
+ $helper->table = $this->table;
+ $helper->module = $this;
+ $helper->default_form_language = $defaultLang;
+ $helper->allow_employee_form_lang = (int) Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG');
+ $helper->identifier = 'id_carousel';
+ $helper->submit_action = 'submitPpCarousel';
+ $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
+ $helper->token = Tools::getAdminTokenLite('AdminModules');
+ $helper->languages = $this->context->controller->getLanguages();
+ $helper->id_language = (int) $this->context->language->id;
+
+ // Fill form values
+ $helper->fields_value['id_carousel'] = $idCarousel;
+ $helper->fields_value['hook_name'] = isset($carousel['hook_name']) ? $carousel['hook_name'] : 'displayHome';
+ $helper->fields_value['custom_hook'] = '';
+ $helper->fields_value['source_type'] = isset($carousel['source_type']) ? $carousel['source_type'] : 'new';
+ $helper->fields_value['id_category'] = isset($carousel['id_category']) ? (int) $carousel['id_category'] : 0;
+ $helper->fields_value['product_ids'] = isset($carousel['product_ids']) ? $carousel['product_ids'] : '';
+ $helper->fields_value['limit_products'] = isset($carousel['limit_products']) ? (int) $carousel['limit_products'] : 12;
+ $helper->fields_value['button_url'] = isset($carousel['button_url']) ? $carousel['button_url'] : '';
+ $helper->fields_value['position'] = isset($carousel['position']) ? (int) $carousel['position'] : 0;
+ $helper->fields_value['active'] = isset($carousel['active']) ? (int) $carousel['active'] : 1;
+
+ foreach ($langs as $lang) {
+ $id = (int) $lang['id_lang'];
+ $langData = $idCarousel ? $this->getCarouselLang($idCarousel, $id) : [];
+ $helper->fields_value['title'][$id] = isset($langData['title']) ? $langData['title'] : '';
+ $helper->fields_value['subtitle'][$id] = isset($langData['subtitle']) ? $langData['subtitle'] : '';
+ $helper->fields_value['button_label'][$id] = isset($langData['button_label']) ? $langData['button_label'] : '';
+ $helper->fields_value['price_suffix'][$id] = isset($langData['price_suffix']) ? $langData['price_suffix'] : '';
+ }
+
+ $formHtml = $helper->generateForm([$fieldsForm]);
+
+ // Inject JS for conditional field visibility
+ $formHtml .= $this->getAdminFormJs();
+
+ return $formHtml;
+ }
+
+ private function getAdminFormJs()
+ {
+ return '
+ ';
+ }
+
+ private function saveCarousel()
+ {
+ $idCarousel = (int) Tools::getValue('id_carousel');
+ $hookName = trim(Tools::getValue('custom_hook'));
+ if (empty($hookName)) {
+ $hookName = trim(Tools::getValue('hook_name'));
+ }
+ if (empty($hookName)) {
+ $hookName = 'displayHome';
+ }
+
+ $sourceType = Tools::getValue('source_type');
+ $idCategory = (int) Tools::getValue('id_category');
+ $productIds = trim(Tools::getValue('product_ids'));
+ $limitProducts = (int) Tools::getValue('limit_products');
+ $buttonUrl = trim(Tools::getValue('button_url'));
+ $position = (int) Tools::getValue('position');
+ $active = (int) Tools::getValue('active');
+
+ if ($limitProducts <= 0) {
+ $limitProducts = 12;
+ }
+
+ // Sanitize manual product IDs
+ if ($sourceType === 'manual' && $productIds) {
+ $ids = array_filter(array_map('intval', explode(',', $productIds)));
+ $productIds = implode(',', $ids);
+ }
+
+ $now = date('Y-m-d H:i:s');
+ $db = Db::getInstance();
+
+ if ($idCarousel > 0) {
+ $db->update('pp_carousel', [
+ 'hook_name' => pSQL($hookName),
+ 'source_type' => pSQL($sourceType),
+ 'id_category' => $idCategory,
+ 'product_ids' => pSQL($productIds),
+ 'limit_products' => $limitProducts,
+ 'button_url' => pSQL($buttonUrl),
+ 'position' => $position,
+ 'active' => $active,
+ 'date_upd' => $now,
+ ], 'id_carousel = ' . $idCarousel);
+ } else {
+ $db->insert('pp_carousel', [
+ 'hook_name' => pSQL($hookName),
+ 'source_type' => pSQL($sourceType),
+ 'id_category' => $idCategory,
+ 'product_ids' => pSQL($productIds),
+ 'limit_products' => $limitProducts,
+ 'button_url' => pSQL($buttonUrl),
+ 'position' => $position,
+ 'active' => $active,
+ 'id_shop' => (int) $this->context->shop->id,
+ 'date_add' => $now,
+ 'date_upd' => $now,
+ ]);
+ $idCarousel = (int) $db->Insert_ID();
+ }
+
+ // Save lang fields
+ $langs = Language::getLanguages(false);
+ foreach ($langs as $lang) {
+ $id = (int) $lang['id_lang'];
+ $title = Tools::substr(trim(Tools::getValue('title_' . $id)), 0, 255);
+ $subtitle = Tools::substr(trim(Tools::getValue('subtitle_' . $id)), 0, 255);
+ $buttonLabel = Tools::substr(trim(Tools::getValue('button_label_' . $id)), 0, 255);
+ $priceSuffix = Tools::substr(trim(Tools::getValue('price_suffix_' . $id)), 0, 64);
+
+ $exists = $db->getValue(
+ 'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'pp_carousel_lang`
+ WHERE id_carousel = ' . $idCarousel . ' AND id_lang = ' . $id
+ );
+
+ $langData = [
+ 'title' => pSQL($title),
+ 'subtitle' => pSQL($subtitle),
+ 'button_label' => pSQL($buttonLabel),
+ 'price_suffix' => pSQL($priceSuffix),
+ ];
+
+ if ($exists) {
+ $db->update('pp_carousel_lang', $langData, 'id_carousel = ' . $idCarousel . ' AND id_lang = ' . $id);
+ } else {
+ $langData['id_carousel'] = $idCarousel;
+ $langData['id_lang'] = $id;
+ $db->insert('pp_carousel_lang', $langData);
+ }
+ }
+
+ // Register custom hook if needed
+ $this->ensureHookRegistered($hookName);
+
+ return $this->displayConfirmation($this->l('Karuzela została zapisana.'));
+ }
+
+ private function deleteCarousel($idCarousel)
+ {
+ if ($idCarousel <= 0) {
+ return '';
+ }
+
+ $db = Db::getInstance();
+ $db->delete('pp_carousel_lang', 'id_carousel = ' . $idCarousel);
+ $db->delete('pp_carousel', 'id_carousel = ' . $idCarousel);
+
+ return $this->displayConfirmation($this->l('Karuzela została usunięta.'));
+ }
+
+ private function toggleCarouselStatus($idCarousel)
+ {
+ if ($idCarousel <= 0) {
+ return '';
+ }
+
+ $current = (int) Db::getInstance()->getValue(
+ 'SELECT active FROM `' . _DB_PREFIX_ . 'pp_carousel` WHERE id_carousel = ' . $idCarousel
+ );
+
+ Db::getInstance()->update('pp_carousel', [
+ 'active' => $current ? 0 : 1,
+ ], 'id_carousel = ' . $idCarousel);
+
+ return $this->displayConfirmation($this->l('Status karuzeli został zmieniony.'));
+ }
+
+ private function getCarousel($idCarousel)
+ {
+ return Db::getInstance()->getRow(
+ 'SELECT * FROM `' . _DB_PREFIX_ . 'pp_carousel` WHERE id_carousel = ' . (int) $idCarousel
+ );
+ }
+
+ private function getCarouselLang($idCarousel, $idLang)
+ {
+ return Db::getInstance()->getRow(
+ 'SELECT * FROM `' . _DB_PREFIX_ . 'pp_carousel_lang`
+ WHERE id_carousel = ' . (int) $idCarousel . ' AND id_lang = ' . (int) $idLang
+ ) ?: [];
+ }
+
+ private function getAvailableHooks()
+ {
+ $hooks = [
+ 'displayHome', 'displayTopColumn', 'displayFooterBefore',
+ 'displayFooter', 'displayLeftColumn', 'displayRightColumn',
+ 'displayOrderConfirmation2', 'displayCrossSellingShoppingCart',
+ ];
+
+ $options = [];
+ foreach ($hooks as $h) {
+ $options[] = ['id' => $h, 'name' => $h];
+ }
+
+ return $options;
+ }
+
+ private function flattenCategories($tree, $depth = 0, &$out = [])
+ {
+ foreach ($tree as $node) {
+ if (!isset($node['id_category'], $node['name'])) {
+ continue;
+ }
+ $prefix = str_repeat('— ', max(0, $depth));
+ $out[] = [
+ 'id' => (int) $node['id_category'],
+ 'name' => $prefix . $node['name'],
+ ];
+ if (!empty($node['children'])) {
+ $this->flattenCategories($node['children'], $depth + 1, $out);
+ }
+ }
+ return $out;
+ }
+
+ private function ensureHookRegistered($hookName)
+ {
+ $idHook = Hook::getIdByName($hookName);
+ if (!$idHook) {
+ $db = Db::getInstance();
+ $db->insert('hook', [
+ 'name' => pSQL($hookName),
+ 'title' => pSQL($hookName),
+ ]);
+ }
+ if (!$this->isRegisteredInHook($hookName)) {
+ $this->registerHook($hookName);
+ }
+ }
+
+ public function isRegisteredInHook($hookName)
+ {
+ $idHook = (int) Hook::getIdByName($hookName);
+ if (!$idHook) {
+ return false;
+ }
+ $count = (int) Db::getInstance()->getValue(
+ 'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'hook_module`
+ WHERE id_hook = ' . $idHook . ' AND id_module = ' . (int) $this->id
+ );
+ return $count > 0;
+ }
+
+ // ─── FRONT HOOKS ────────────────────────────────────────────
+
+ public function hookDisplayHeader()
+ {
+ $this->context->controller->registerStylesheet(
+ 'pp_carousel_swiper_css',
+ 'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.css',
+ ['media' => 'all', 'priority' => 150]
+ );
+ $this->context->controller->registerStylesheet(
+ 'pp_carousel_css',
+ 'modules/' . $this->name . '/views/css/pp_carousel.css',
+ ['media' => 'all', 'priority' => 151]
+ );
+ $this->context->controller->registerJavascript(
+ 'pp_carousel_swiper_js',
+ 'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.js',
+ ['position' => 'bottom', 'priority' => 150]
+ );
+ $this->context->controller->registerJavascript(
+ 'pp_carousel_js',
+ 'modules/' . $this->name . '/views/js/pp_carousel.js',
+ ['position' => 'bottom', 'priority' => 151]
+ );
+ }
+
+ public function hookDisplayHome($params)
+ {
+ return $this->renderCarouselsForHook('displayHome');
+ }
+
+ public function hookDisplayTopColumn($params)
+ {
+ return $this->renderCarouselsForHook('displayTopColumn');
+ }
+
+ public function hookDisplayFooterBefore($params)
+ {
+ return $this->renderCarouselsForHook('displayFooterBefore');
+ }
+
+ public function hookDisplayFooter($params)
+ {
+ return $this->renderCarouselsForHook('displayFooter');
+ }
+
+ public function hookDisplayLeftColumn($params)
+ {
+ return $this->renderCarouselsForHook('displayLeftColumn');
+ }
+
+ public function hookDisplayRightColumn($params)
+ {
+ return $this->renderCarouselsForHook('displayRightColumn');
+ }
+
+ /**
+ * Catch-all: render carousels for any hook not explicitly defined above.
+ */
+ public function __call($method, $args)
+ {
+ if (strpos($method, 'hookDisplay') === 0) {
+ $hookName = lcfirst(substr($method, 4));
+ return $this->renderCarouselsForHook($hookName);
+ }
+ return '';
+ }
+
+ // ─── RENDERING ──────────────────────────────────────────────
+
+ private function renderCarouselsForHook($hookName)
+ {
+ $carousels = Db::getInstance()->executeS(
+ 'SELECT c.*, cl.title, cl.subtitle, cl.button_label, cl.price_suffix
+ FROM `' . _DB_PREFIX_ . 'pp_carousel` c
+ LEFT JOIN `' . _DB_PREFIX_ . 'pp_carousel_lang` cl
+ ON c.id_carousel = cl.id_carousel AND cl.id_lang = ' . (int) $this->context->language->id . '
+ WHERE c.hook_name = "' . pSQL($hookName) . '"
+ AND c.active = 1
+ AND c.id_shop = ' . (int) $this->context->shop->id . '
+ ORDER BY c.position ASC, c.id_carousel ASC'
+ );
+
+ if (empty($carousels)) {
+ return '';
+ }
+
+ $html = '';
+ foreach ($carousels as $carousel) {
+ $products = $this->getProductsByCarousel($carousel);
+ if (empty($products)) {
+ continue;
+ }
+
+ $buttonUrl = trim($carousel['button_url']);
+ if (empty($buttonUrl) && $carousel['source_type'] === 'category' && $carousel['id_category'] > 0) {
+ $cat = new Category((int) $carousel['id_category'], (int) $this->context->language->id);
+ if (Validate::isLoadedObject($cat)) {
+ $buttonUrl = $this->context->link->getCategoryLink($cat);
+ }
+ }
+
+ $this->context->smarty->assign([
+ 'ppc_id' => (int) $carousel['id_carousel'],
+ 'ppc_title' => $carousel['title'] ?: '',
+ 'ppc_subtitle' => $carousel['subtitle'] ?: '',
+ 'ppc_button_label' => $carousel['button_label'] ?: '',
+ 'ppc_button_url' => $buttonUrl,
+ 'ppc_price_suffix' => $carousel['price_suffix'] ?: '',
+ 'ppc_products' => $products,
+ ]);
+
+ $html .= $this->fetch('module:' . $this->name . '/views/templates/hook/pp_carousel.tpl');
+ }
+
+ return $html;
+ }
+
+ // ─── PRODUCT SOURCES ────────────────────────────────────────
+
+ private function getProductsByCarousel($carousel)
+ {
+ $limit = (int) $carousel['limit_products'];
+ if ($limit <= 0) {
+ $limit = 12;
+ }
+
+ switch ($carousel['source_type']) {
+ case 'new':
+ return $this->getNewProducts($limit);
+ case 'bestseller':
+ return $this->getBestsellers($limit);
+ case 'category':
+ return $this->getCategoryProducts((int) $carousel['id_category'], $limit);
+ case 'manual':
+ return $this->getManualProducts($carousel['product_ids'], $limit);
+ default:
+ return [];
+ }
+ }
+
+ private function getNewProducts($limit)
+ {
+ $idLang = (int) $this->context->language->id;
+ $raw = Product::getNewProducts($idLang, 0, $limit);
+ return is_array($raw) ? $this->presentProducts($raw) : [];
+ }
+
+ private function getBestsellers($limit)
+ {
+ $idLang = (int) $this->context->language->id;
+ $raw = ProductSale::getBestSales($idLang, 0, $limit);
+ return is_array($raw) ? $this->presentProducts($raw) : [];
+ }
+
+ private function getCategoryProducts($idCategory, $limit)
+ {
+ if ($idCategory <= 0) {
+ return [];
+ }
+ $idLang = (int) $this->context->language->id;
+ $category = new Category($idCategory, $idLang);
+ if (!Validate::isLoadedObject($category)) {
+ return [];
+ }
+ $raw = $category->getProducts($idLang, 1, $limit, 'position', 'asc');
+ return is_array($raw) ? $this->presentProducts($raw) : [];
+ }
+
+ private function getManualProducts($productIdsStr, $limit)
+ {
+ if (empty($productIdsStr)) {
+ return [];
+ }
+
+ $ids = array_filter(array_map('intval', explode(',', $productIdsStr)));
+ if (empty($ids)) {
+ return [];
+ }
+
+ $idLang = (int) $this->context->language->id;
+ $idShop = (int) $this->context->shop->id;
+
+ $sql = 'SELECT p.*, pl.`name`, pl.`description_short`, pl.`link_rewrite`,
+ cl.`name` AS category_default, cl.`link_rewrite` AS category_link_rewrite,
+ i.`id_image`, il.`legend`,
+ m.`name` AS manufacturer_name,
+ p.`id_category_default`
+ FROM `' . _DB_PREFIX_ . 'product` p
+ LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl
+ ON p.id_product = pl.id_product AND pl.id_lang = ' . $idLang . ' AND pl.id_shop = ' . $idShop . '
+ LEFT JOIN `' . _DB_PREFIX_ . 'category_lang` cl
+ ON p.id_category_default = cl.id_category AND cl.id_lang = ' . $idLang . ' AND cl.id_shop = ' . $idShop . '
+ LEFT JOIN `' . _DB_PREFIX_ . 'image` i
+ ON p.id_product = i.id_product AND i.cover = 1
+ LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il
+ ON i.id_image = il.id_image AND il.id_lang = ' . $idLang . '
+ LEFT JOIN `' . _DB_PREFIX_ . 'manufacturer` m
+ ON p.id_manufacturer = m.id_manufacturer
+ LEFT JOIN `' . _DB_PREFIX_ . 'product_shop` ps
+ ON p.id_product = ps.id_product AND ps.id_shop = ' . $idShop . '
+ WHERE p.id_product IN (' . implode(',', $ids) . ')
+ AND ps.active = 1
+ LIMIT ' . (int) $limit;
+
+ $raw = Db::getInstance()->executeS($sql);
+ return is_array($raw) ? $this->presentProducts($raw) : [];
+ }
+
+ private function presentProducts(array $rawProducts)
+ {
+ $assembler = new \ProductAssembler($this->context);
+ $presenterFactory = new \ProductPresenterFactory($this->context);
+ $presentationSettings = $presenterFactory->getPresentationSettings();
+ $presenter = $presenterFactory->getPresenter();
+
+ $products = [];
+ foreach ($rawProducts as $raw) {
+ try {
+ $assembled = $assembler->assembleProduct($raw);
+ $products[] = $presenter->present(
+ $presentationSettings,
+ $assembled,
+ $this->context->language
+ );
+ } catch (Exception $e) {
+ continue;
+ }
+ }
+
+ return $products;
+ }
+}
diff --git a/modules/pp_carousel/sql/install.sql b/modules/pp_carousel/sql/install.sql
new file mode 100644
index 0000000..940f6db
--- /dev/null
+++ b/modules/pp_carousel/sql/install.sql
@@ -0,0 +1,27 @@
+CREATE TABLE IF NOT EXISTS `PREFIX_pp_carousel` (
+ `id_carousel` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `hook_name` VARCHAR(128) NOT NULL DEFAULT 'displayHome',
+ `source_type` VARCHAR(20) NOT NULL DEFAULT 'new',
+ `id_category` INT(11) UNSIGNED NOT NULL DEFAULT 0,
+ `product_ids` TEXT,
+ `limit_products` INT(11) UNSIGNED NOT NULL DEFAULT 12,
+ `button_url` VARCHAR(512) DEFAULT '',
+ `position` INT(11) UNSIGNED NOT NULL DEFAULT 0,
+ `active` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
+ `id_shop` INT(11) UNSIGNED NOT NULL DEFAULT 1,
+ `date_add` DATETIME NOT NULL,
+ `date_upd` DATETIME NOT NULL,
+ PRIMARY KEY (`id_carousel`),
+ KEY `hook_name` (`hook_name`),
+ KEY `active` (`active`)
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `PREFIX_pp_carousel_lang` (
+ `id_carousel` INT(11) UNSIGNED NOT NULL,
+ `id_lang` INT(11) UNSIGNED NOT NULL,
+ `title` VARCHAR(255) DEFAULT '',
+ `subtitle` VARCHAR(255) DEFAULT '',
+ `button_label` VARCHAR(255) DEFAULT '',
+ `price_suffix` VARCHAR(64) DEFAULT '',
+ PRIMARY KEY (`id_carousel`, `id_lang`)
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
diff --git a/modules/pp_carousel/sql/uninstall.sql b/modules/pp_carousel/sql/uninstall.sql
new file mode 100644
index 0000000..b0e3485
--- /dev/null
+++ b/modules/pp_carousel/sql/uninstall.sql
@@ -0,0 +1,2 @@
+DROP TABLE IF EXISTS `PREFIX_pp_carousel_lang`;
+DROP TABLE IF EXISTS `PREFIX_pp_carousel`;
diff --git a/modules/pp_carousel/views/css/pp_carousel.css b/modules/pp_carousel/views/css/pp_carousel.css
new file mode 100644
index 0000000..b5809b3
--- /dev/null
+++ b/modules/pp_carousel/views/css/pp_carousel.css
@@ -0,0 +1,179 @@
+.pp-carousel {
+ margin: 40px 0;
+}
+
+.pp-carousel__header {
+ margin-bottom: 18px;
+}
+
+.pp-carousel__title {
+ font-size: 42px;
+ line-height: 1.1;
+ margin: 0 0 6px 0;
+ font-weight: 500;
+}
+
+.pp-carousel__subtitle {
+ font-size: 44px;
+ line-height: 1.1;
+ font-weight: 300;
+ opacity: .85;
+}
+
+.pp-carousel__slider {
+ position: relative;
+ padding: 10px 0 0 0;
+}
+
+.pp-carousel__card {
+ display: block;
+}
+
+.pp-carousel__image {
+ display: block;
+ border-radius: 2px;
+ overflow: hidden;
+ background: #f6f6f6;
+ position: relative;
+}
+
+.pp-carousel__image img {
+ width: 100%;
+ height: auto;
+ display: block;
+ aspect-ratio: 1 / 1;
+ object-fit: cover;
+}
+
+.pp-carousel__label {
+ position: absolute;
+ top: 12px;
+ left: 12px;
+ background: rgba(0, 0, 0, .55);
+ color: #fff;
+ font-size: 12px;
+ font-weight: 500;
+ padding: 4px 12px;
+ border-radius: 3px;
+ letter-spacing: .02em;
+ text-transform: capitalize;
+ pointer-events: none;
+}
+
+.pp-carousel__meta {
+ display: flex;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 14px 2px 0 2px;
+ align-items: baseline;
+}
+
+.pp-carousel__name {
+ font-size: 18px;
+ font-weight: 600;
+ color: inherit;
+ text-decoration: none;
+}
+
+.pp-carousel__name:hover {
+ text-decoration: underline;
+}
+
+.pp-carousel__price {
+ font-size: 16px;
+ opacity: .7;
+ white-space: nowrap;
+}
+
+.pp-carousel__priceSuffix {
+ margin-left: 2px;
+}
+
+.pp-carousel__footer {
+ margin-top: 22px;
+}
+
+.pp-carousel__more {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ text-decoration: none;
+ opacity: .75;
+ font-size: 16px;
+ color: inherit;
+}
+
+.pp-carousel__more:before {
+ content: "";
+ display: inline-block;
+ width: 28px;
+ height: 1px;
+ background: currentColor;
+ opacity: .6;
+}
+
+.pp-carousel__more:hover {
+ opacity: 1;
+}
+
+/* Navigation arrows */
+.pp-carousel__nav .pp-carousel__prev,
+.pp-carousel__nav .pp-carousel__next {
+ position: absolute;
+ top: 45%;
+ width: 40px;
+ height: 40px;
+ transform: translateY(-50%);
+ cursor: pointer;
+ opacity: .6;
+ z-index: 3;
+ transition: opacity .2s;
+}
+
+.pp-carousel__nav .pp-carousel__prev:hover,
+.pp-carousel__nav .pp-carousel__next:hover {
+ opacity: 1;
+}
+
+.pp-carousel__nav .pp-carousel__prev { left: -10px; }
+.pp-carousel__nav .pp-carousel__next { right: -10px; }
+
+.pp-carousel__nav .pp-carousel__prev:after,
+.pp-carousel__nav .pp-carousel__next:after {
+ content: "";
+ display: block;
+ width: 10px;
+ height: 10px;
+ border-right: 2px solid currentColor;
+ border-bottom: 2px solid currentColor;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+}
+
+.pp-carousel__nav .pp-carousel__prev:after {
+ transform: translate(-50%, -50%) rotate(135deg);
+}
+
+.pp-carousel__nav .pp-carousel__next:after {
+ transform: translate(-50%, -50%) rotate(-45deg);
+}
+
+.pp-carousel__nav .swiper-button-disabled {
+ opacity: .2;
+ cursor: default;
+}
+
+/* Responsive */
+@media (max-width: 992px) {
+ .pp-carousel__title { font-size: 34px; }
+ .pp-carousel__subtitle { font-size: 34px; }
+ .pp-carousel__nav .pp-carousel__prev { left: 0; }
+ .pp-carousel__nav .pp-carousel__next { right: 0; }
+}
+
+@media (max-width: 576px) {
+ .pp-carousel__title { font-size: 26px; }
+ .pp-carousel__subtitle { font-size: 26px; }
+ .pp-carousel__name { font-size: 16px; }
+}
diff --git a/modules/pp_carousel/views/js/pp_carousel.js b/modules/pp_carousel/views/js/pp_carousel.js
new file mode 100644
index 0000000..9d799b1
--- /dev/null
+++ b/modules/pp_carousel/views/js/pp_carousel.js
@@ -0,0 +1,23 @@
+document.addEventListener('DOMContentLoaded', function () {
+ if (typeof Swiper === 'undefined') return;
+
+ document.querySelectorAll('.pp-carousel__slider.swiper').forEach(function (el) {
+ var section = el.closest('.pp-carousel');
+ if (!section) return;
+
+ new Swiper(el, {
+ slidesPerView: 3,
+ spaceBetween: 26,
+ loop: false,
+ navigation: {
+ nextEl: section.querySelector('.pp-carousel__next'),
+ prevEl: section.querySelector('.pp-carousel__prev')
+ },
+ breakpoints: {
+ 0: { slidesPerView: 1.15, spaceBetween: 16 },
+ 576: { slidesPerView: 2, spaceBetween: 18 },
+ 992: { slidesPerView: 3, spaceBetween: 26 }
+ }
+ });
+ });
+});
diff --git a/modules/pp_carousel/views/lib/swiper/swiper-bundle.min.css b/modules/pp_carousel/views/lib/swiper/swiper-bundle.min.css
new file mode 100644
index 0000000..c5bf0fb
--- /dev/null
+++ b/modules/pp_carousel/views/lib/swiper/swiper-bundle.min.css
@@ -0,0 +1,13 @@
+/**
+ * Swiper 12.0.3
+ * Most modern mobile touch slider and framework with hardware accelerated transitions
+ * https://swiperjs.com
+ *
+ * Copyright 2014-2025 Vladimir Kharlampidi
+ *
+ * Released under the MIT License
+ *
+ * Released on: October 21, 2025
+ */
+
+:root{--swiper-theme-color:#007aff}:host{display:block;margin-left:auto;margin-right:auto;position:relative;z-index:1}.swiper{display:block;list-style:none;margin-left:auto;margin-right:auto;overflow:hidden;padding:0;position:relative;z-index:1}.swiper-vertical>.swiper-wrapper{flex-direction:column}.swiper-wrapper{box-sizing:initial;display:flex;height:100%;position:relative;transition-property:transform;transition-timing-function:var(--swiper-wrapper-transition-timing-function,initial);width:100%;z-index:1}.swiper-android .swiper-slide,.swiper-ios .swiper-slide,.swiper-wrapper{transform:translateZ(0)}.swiper-horizontal{touch-action:pan-y}.swiper-vertical{touch-action:pan-x}.swiper-slide{display:block;flex-shrink:0;height:100%;position:relative;transition-property:transform;width:100%}.swiper-slide-invisible-blank{visibility:hidden}.swiper-autoheight,.swiper-autoheight .swiper-slide{height:auto}.swiper-autoheight .swiper-wrapper{align-items:flex-start;transition-property:transform,height}.swiper-backface-hidden .swiper-slide{backface-visibility:hidden;transform:translateZ(0)}.swiper-3d.swiper-css-mode .swiper-wrapper{perspective:1200px}.swiper-3d .swiper-wrapper{transform-style:preserve-3d}.swiper-3d{perspective:1200px;.swiper-cube-shadow,.swiper-slide{transform-style:preserve-3d}}.swiper-css-mode{>.swiper-wrapper{overflow:auto;scrollbar-width:none;-ms-overflow-style:none;&::-webkit-scrollbar{display:none}}>.swiper-wrapper>.swiper-slide{scroll-snap-align:start start}&.swiper-horizontal{>.swiper-wrapper{scroll-snap-type:x mandatory}}&.swiper-vertical{>.swiper-wrapper{scroll-snap-type:y mandatory}}&.swiper-free-mode{>.swiper-wrapper{scroll-snap-type:none}>.swiper-wrapper>.swiper-slide{scroll-snap-align:none}}&.swiper-centered{>.swiper-wrapper:before{content:"";flex-shrink:0;order:9999}>.swiper-wrapper>.swiper-slide{scroll-snap-align:center center;scroll-snap-stop:always}}&.swiper-centered.swiper-horizontal{>.swiper-wrapper>.swiper-slide:first-child{margin-inline-start:var(--swiper-centered-offset-before)}>.swiper-wrapper:before{height:100%;min-height:1px;width:var(--swiper-centered-offset-after)}}&.swiper-centered.swiper-vertical{>.swiper-wrapper>.swiper-slide:first-child{margin-block-start:var(--swiper-centered-offset-before)}>.swiper-wrapper:before{height:var(--swiper-centered-offset-after);min-width:1px;width:100%}}}.swiper-3d{.swiper-slide-shadow,.swiper-slide-shadow-bottom,.swiper-slide-shadow-left,.swiper-slide-shadow-right,.swiper-slide-shadow-top{height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%;z-index:10}.swiper-slide-shadow{background:#00000026}.swiper-slide-shadow-left{background-image:linear-gradient(270deg,#00000080,#0000)}.swiper-slide-shadow-right{background-image:linear-gradient(90deg,#00000080,#0000)}.swiper-slide-shadow-top{background-image:linear-gradient(0deg,#00000080,#0000)}.swiper-slide-shadow-bottom{background-image:linear-gradient(180deg,#00000080,#0000)}}.swiper-lazy-preloader{border:4px solid var(--swiper-preloader-color,var(--swiper-theme-color));border-radius:50%;border-top:4px solid #0000;box-sizing:border-box;height:42px;left:50%;margin-left:-21px;margin-top:-21px;position:absolute;top:50%;transform-origin:50%;width:42px;z-index:10}.swiper-watch-progress .swiper-slide-visible,.swiper:not(.swiper-watch-progress){.swiper-lazy-preloader{animation:swiper-preloader-spin 1s linear infinite}}.swiper-lazy-preloader-white{--swiper-preloader-color:#fff}.swiper-lazy-preloader-black{--swiper-preloader-color:#000}@keyframes swiper-preloader-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.swiper-virtual .swiper-slide{-webkit-backface-visibility:hidden;transform:translateZ(0)}.swiper-virtual.swiper-css-mode{.swiper-wrapper:after{content:"";left:0;pointer-events:none;position:absolute;top:0}}.swiper-virtual.swiper-css-mode.swiper-horizontal{.swiper-wrapper:after{height:1px;width:var(--swiper-virtual-size)}}.swiper-virtual.swiper-css-mode.swiper-vertical{.swiper-wrapper:after{height:var(--swiper-virtual-size);width:1px}}:root{--swiper-navigation-size:44px}.swiper-button-next,.swiper-button-prev{align-items:center;color:var(--swiper-navigation-color,var(--swiper-theme-color));cursor:pointer;display:flex;height:var(--swiper-navigation-size);justify-content:center;position:absolute;width:var(--swiper-navigation-size);z-index:10;&.swiper-button-disabled{cursor:auto;opacity:.35;pointer-events:none}&.swiper-button-hidden{cursor:auto;opacity:0;pointer-events:none}.swiper-navigation-disabled &{display:none!important}svg{height:100%;object-fit:contain;transform-origin:center;width:100%;fill:currentColor;pointer-events:none}}.swiper-button-lock{display:none}.swiper-button-next,.swiper-button-prev{margin-top:calc(0px - var(--swiper-navigation-size)/2);top:var(--swiper-navigation-top-offset,50%)}.swiper-button-prev{left:var(--swiper-navigation-sides-offset,4px);right:auto;.swiper-navigation-icon{transform:rotate(180deg)}}.swiper-button-next{left:auto;right:var(--swiper-navigation-sides-offset,4px)}.swiper-horizontal{.swiper-button-next,.swiper-button-prev,~.swiper-button-next,~.swiper-button-prev{margin-left:0;margin-top:calc(0px - var(--swiper-navigation-size)/2);top:var(--swiper-navigation-top-offset,50%)}&.swiper-rtl .swiper-button-next,&.swiper-rtl~.swiper-button-next,&~.swiper-button-prev,.swiper-button-prev{left:var(--swiper-navigation-sides-offset,4px);right:auto}&.swiper-rtl .swiper-button-prev,&.swiper-rtl~.swiper-button-prev,&~.swiper-button-next,.swiper-button-next{left:auto;right:var(--swiper-navigation-sides-offset,4px)}&.swiper-rtl .swiper-button-next,&.swiper-rtl~.swiper-button-next,&~.swiper-button-prev,.swiper-button-prev{.swiper-navigation-icon{transform:rotate(180deg)}}&.swiper-rtl .swiper-button-prev,&.swiper-rtl~.swiper-button-prev{.swiper-navigation-icon{transform:rotate(0deg)}}}.swiper-vertical{.swiper-button-next,.swiper-button-prev,~.swiper-button-next,~.swiper-button-prev{left:var(--swiper-navigation-top-offset,50%);margin-left:calc(0px - var(--swiper-navigation-size)/2);margin-top:0;right:auto}.swiper-button-prev,~.swiper-button-prev{bottom:auto;top:var(--swiper-navigation-sides-offset,4px);.swiper-navigation-icon{transform:rotate(-90deg)}}.swiper-button-next,~.swiper-button-next{bottom:var(--swiper-navigation-sides-offset,4px);top:auto;.swiper-navigation-icon{transform:rotate(90deg)}}}.swiper-pagination{position:absolute;text-align:center;transform:translateZ(0);transition:opacity .3s;z-index:10;&.swiper-pagination-hidden{opacity:0}&.swiper-pagination-disabled,.swiper-pagination-disabled>&{display:none!important}}.swiper-horizontal>.swiper-pagination-bullets,.swiper-pagination-bullets.swiper-pagination-horizontal,.swiper-pagination-custom,.swiper-pagination-fraction{bottom:var(--swiper-pagination-bottom,8px);left:0;top:var(--swiper-pagination-top,auto);width:100%}.swiper-pagination-bullets-dynamic{font-size:0;overflow:hidden;.swiper-pagination-bullet{position:relative;transform:scale(.33)}.swiper-pagination-bullet-active,.swiper-pagination-bullet-active-main{transform:scale(1)}.swiper-pagination-bullet-active-prev{transform:scale(.66)}.swiper-pagination-bullet-active-prev-prev{transform:scale(.33)}.swiper-pagination-bullet-active-next{transform:scale(.66)}.swiper-pagination-bullet-active-next-next{transform:scale(.33)}}.swiper-pagination-bullet{background:var(--swiper-pagination-bullet-inactive-color,#000);border-radius:var(--swiper-pagination-bullet-border-radius,50%);display:inline-block;height:var(--swiper-pagination-bullet-height,var(--swiper-pagination-bullet-size,8px));opacity:var(--swiper-pagination-bullet-inactive-opacity,.2);width:var(--swiper-pagination-bullet-width,var(--swiper-pagination-bullet-size,8px));button&{appearance:none;border:none;box-shadow:none;margin:0;padding:0}.swiper-pagination-clickable &{cursor:pointer}&:only-child{display:none!important}}.swiper-pagination-bullet-active{background:var(--swiper-pagination-color,var(--swiper-theme-color));opacity:var(--swiper-pagination-bullet-opacity,1)}.swiper-pagination-vertical.swiper-pagination-bullets,.swiper-vertical>.swiper-pagination-bullets{left:var(--swiper-pagination-left,auto);right:var(--swiper-pagination-right,8px);top:50%;transform:translate3d(0,-50%,0);.swiper-pagination-bullet{display:block;margin:var(--swiper-pagination-bullet-vertical-gap,6px) 0}&.swiper-pagination-bullets-dynamic{top:50%;transform:translateY(-50%);width:8px;.swiper-pagination-bullet{display:inline-block;transition:transform .2s,top .2s}}}.swiper-horizontal>.swiper-pagination-bullets,.swiper-pagination-horizontal.swiper-pagination-bullets{.swiper-pagination-bullet{margin:0 var(--swiper-pagination-bullet-horizontal-gap,4px)}&.swiper-pagination-bullets-dynamic{left:50%;transform:translateX(-50%);white-space:nowrap;.swiper-pagination-bullet{transition:transform .2s,left .2s}}}.swiper-horizontal.swiper-rtl>.swiper-pagination-bullets-dynamic .swiper-pagination-bullet{transition:transform .2s,right .2s}.swiper-pagination-fraction{color:var(--swiper-pagination-fraction-color,inherit)}.swiper-pagination-progressbar{background:var(--swiper-pagination-progressbar-bg-color,#00000040);position:absolute;.swiper-pagination-progressbar-fill{background:var(--swiper-pagination-color,var(--swiper-theme-color));height:100%;left:0;position:absolute;top:0;transform:scale(0);transform-origin:left top;width:100%}.swiper-rtl & .swiper-pagination-progressbar-fill{transform-origin:right top}&.swiper-pagination-horizontal,&.swiper-pagination-vertical.swiper-pagination-progressbar-opposite,.swiper-horizontal>&,.swiper-vertical>&.swiper-pagination-progressbar-opposite{height:var(--swiper-pagination-progressbar-size,4px);left:0;top:0;width:100%}&.swiper-pagination-horizontal.swiper-pagination-progressbar-opposite,&.swiper-pagination-vertical,.swiper-horizontal>&.swiper-pagination-progressbar-opposite,.swiper-vertical>&{height:100%;left:0;top:0;width:var(--swiper-pagination-progressbar-size,4px)}}.swiper-pagination-lock{display:none}.swiper-scrollbar{background:var(--swiper-scrollbar-bg-color,#0000001a);border-radius:var(--swiper-scrollbar-border-radius,10px);position:relative;touch-action:none;&.swiper-scrollbar-disabled,.swiper-scrollbar-disabled>&{display:none!important}&.swiper-scrollbar-horizontal,.swiper-horizontal>&{bottom:var(--swiper-scrollbar-bottom,4px);height:var(--swiper-scrollbar-size,4px);left:var(--swiper-scrollbar-sides-offset,1%);position:absolute;top:var(--swiper-scrollbar-top,auto);width:calc(100% - var(--swiper-scrollbar-sides-offset, 1%)*2);z-index:50}&.swiper-scrollbar-vertical,.swiper-vertical>&{height:calc(100% - var(--swiper-scrollbar-sides-offset, 1%)*2);left:var(--swiper-scrollbar-left,auto);position:absolute;right:var(--swiper-scrollbar-right,4px);top:var(--swiper-scrollbar-sides-offset,1%);width:var(--swiper-scrollbar-size,4px);z-index:50}}.swiper-scrollbar-drag{background:var(--swiper-scrollbar-drag-bg-color,#00000080);border-radius:var(--swiper-scrollbar-border-radius,10px);height:100%;left:0;position:relative;top:0;width:100%}.swiper-scrollbar-cursor-drag{cursor:move}.swiper-scrollbar-lock{display:none}.swiper-zoom-container{align-items:center;display:flex;height:100%;justify-content:center;text-align:center;width:100%;>canvas,>img,>svg{max-height:100%;max-width:100%;object-fit:contain}}.swiper-slide-zoomed{cursor:move;touch-action:none}.swiper .swiper-notification{left:0;opacity:0;pointer-events:none;position:absolute;top:0;z-index:-1000}.swiper-free-mode>.swiper-wrapper{margin:0 auto;transition-timing-function:ease-out}.swiper-grid>.swiper-wrapper{flex-wrap:wrap}.swiper-grid-column>.swiper-wrapper{flex-direction:column;flex-wrap:wrap}.swiper-fade{&.swiper-free-mode{.swiper-slide{transition-timing-function:ease-out}}.swiper-slide{pointer-events:none;transition-property:opacity;.swiper-slide{pointer-events:none}}.swiper-slide-active{pointer-events:auto;& .swiper-slide-active{pointer-events:auto}}}.swiper.swiper-cube{overflow:visible}.swiper-cube{.swiper-slide{backface-visibility:hidden;height:100%;pointer-events:none;transform-origin:0 0;visibility:hidden;width:100%;z-index:1;.swiper-slide{pointer-events:none}}&.swiper-rtl .swiper-slide{transform-origin:100% 0}.swiper-slide-active{&,& .swiper-slide-active{pointer-events:auto}}.swiper-slide-active,.swiper-slide-next,.swiper-slide-prev{pointer-events:auto;visibility:visible}.swiper-cube-shadow{bottom:0;height:100%;left:0;opacity:.6;position:absolute;width:100%;z-index:0;&:before{background:#000;bottom:0;content:"";filter:blur(50px);left:0;position:absolute;right:0;top:0}}}.swiper-cube{.swiper-slide-next+.swiper-slide{pointer-events:auto;visibility:visible}}.swiper-cube{.swiper-slide-shadow-cube.swiper-slide-shadow-bottom,.swiper-slide-shadow-cube.swiper-slide-shadow-left,.swiper-slide-shadow-cube.swiper-slide-shadow-right,.swiper-slide-shadow-cube.swiper-slide-shadow-top{backface-visibility:hidden;z-index:0}}.swiper.swiper-flip{overflow:visible}.swiper-flip{.swiper-slide{backface-visibility:hidden;pointer-events:none;z-index:1;.swiper-slide{pointer-events:none}}.swiper-slide-active{&,& .swiper-slide-active{pointer-events:auto}}}.swiper-flip{.swiper-slide-shadow-flip.swiper-slide-shadow-bottom,.swiper-slide-shadow-flip.swiper-slide-shadow-left,.swiper-slide-shadow-flip.swiper-slide-shadow-right,.swiper-slide-shadow-flip.swiper-slide-shadow-top{backface-visibility:hidden;z-index:0}}.swiper-creative{.swiper-slide{backface-visibility:hidden;overflow:hidden;transition-property:transform,opacity,height}}.swiper.swiper-cards{overflow:visible}.swiper-cards{.swiper-slide{backface-visibility:hidden;overflow:hidden;transform-origin:center bottom}}
\ No newline at end of file
diff --git a/modules/pp_carousel/views/lib/swiper/swiper-bundle.min.js b/modules/pp_carousel/views/lib/swiper/swiper-bundle.min.js
new file mode 100644
index 0000000..9251265
--- /dev/null
+++ b/modules/pp_carousel/views/lib/swiper/swiper-bundle.min.js
@@ -0,0 +1,7661 @@
+/**
+ * Swiper 12.0.3
+ * Most modern mobile touch slider and framework with hardware accelerated transitions
+ * https://swiperjs.com
+ *
+ * Copyright 2014-2025 Vladimir Kharlampidi
+ *
+ * Released under the MIT License
+ *
+ * Released on: October 21, 2025
+ */
+
+var Swiper = (function () {
+ 'use strict'
+ function e(e) {
+ return (
+ null !== e &&
+ 'object' == typeof e &&
+ 'constructor' in e &&
+ e.constructor === Object
+ )
+ }
+ function t(s = {}, a = {}) {
+ const i = ['__proto__', 'constructor', 'prototype']
+ Object.keys(a)
+ .filter((e) => i.indexOf(e) < 0)
+ .forEach((i) => {
+ void 0 === s[i]
+ ? (s[i] = a[i])
+ : e(a[i]) && e(s[i]) && Object.keys(a[i]).length > 0 && t(s[i], a[i])
+ })
+ }
+ const s = {
+ body: {},
+ addEventListener() {},
+ removeEventListener() {},
+ activeElement: { blur() {}, nodeName: '' },
+ querySelector: () => null,
+ querySelectorAll: () => [],
+ getElementById: () => null,
+ createEvent: () => ({ initEvent() {} }),
+ createElement: () => ({
+ children: [],
+ childNodes: [],
+ style: {},
+ setAttribute() {},
+ getElementsByTagName: () => [],
+ }),
+ createElementNS: () => ({}),
+ importNode: () => null,
+ location: {
+ hash: '',
+ host: '',
+ hostname: '',
+ href: '',
+ origin: '',
+ pathname: '',
+ protocol: '',
+ search: '',
+ },
+ }
+ function a() {
+ const e = 'undefined' != typeof document ? document : {}
+ return t(e, s), e
+ }
+ const i = {
+ document: s,
+ navigator: { userAgent: '' },
+ location: {
+ hash: '',
+ host: '',
+ hostname: '',
+ href: '',
+ origin: '',
+ pathname: '',
+ protocol: '',
+ search: '',
+ },
+ history: { replaceState() {}, pushState() {}, go() {}, back() {} },
+ CustomEvent: function () {
+ return this
+ },
+ addEventListener() {},
+ removeEventListener() {},
+ getComputedStyle: () => ({ getPropertyValue: () => '' }),
+ Image() {},
+ Date() {},
+ screen: {},
+ setTimeout() {},
+ clearTimeout() {},
+ matchMedia: () => ({}),
+ requestAnimationFrame: (e) =>
+ 'undefined' == typeof setTimeout ? (e(), null) : setTimeout(e, 0),
+ cancelAnimationFrame(e) {
+ 'undefined' != typeof setTimeout && clearTimeout(e)
+ },
+ }
+ function r() {
+ const e = 'undefined' != typeof window ? window : {}
+ return t(e, i), e
+ }
+ function n(e = '') {
+ return e
+ .trim()
+ .split(' ')
+ .filter((e) => !!e.trim())
+ }
+ function l(e, t = 0) {
+ return setTimeout(e, t)
+ }
+ function o() {
+ return Date.now()
+ }
+ function d(e, t = 'x') {
+ const s = r()
+ let a, i, n
+ const l = (function (e) {
+ const t = r()
+ let s
+ return (
+ t.getComputedStyle && (s = t.getComputedStyle(e, null)),
+ !s && e.currentStyle && (s = e.currentStyle),
+ s || (s = e.style),
+ s
+ )
+ })(e)
+ return (
+ s.WebKitCSSMatrix
+ ? ((i = l.transform || l.webkitTransform),
+ i.split(',').length > 6 &&
+ (i = i
+ .split(', ')
+ .map((e) => e.replace(',', '.'))
+ .join(', ')),
+ (n = new s.WebKitCSSMatrix('none' === i ? '' : i)))
+ : ((n =
+ l.MozTransform ||
+ l.OTransform ||
+ l.MsTransform ||
+ l.msTransform ||
+ l.transform ||
+ l
+ .getPropertyValue('transform')
+ .replace('translate(', 'matrix(1, 0, 0, 1,')),
+ (a = n.toString().split(','))),
+ 'x' === t &&
+ (i = s.WebKitCSSMatrix
+ ? n.m41
+ : 16 === a.length
+ ? parseFloat(a[12])
+ : parseFloat(a[4])),
+ 'y' === t &&
+ (i = s.WebKitCSSMatrix
+ ? n.m42
+ : 16 === a.length
+ ? parseFloat(a[13])
+ : parseFloat(a[5])),
+ i || 0
+ )
+ }
+ function c(e) {
+ return (
+ 'object' == typeof e &&
+ null !== e &&
+ e.constructor &&
+ 'Object' === Object.prototype.toString.call(e).slice(8, -1)
+ )
+ }
+ function p(e) {
+ return 'undefined' != typeof window && void 0 !== window.HTMLElement
+ ? e instanceof HTMLElement
+ : e && (1 === e.nodeType || 11 === e.nodeType)
+ }
+ function u(...e) {
+ const t = Object(e[0]),
+ s = ['__proto__', 'constructor', 'prototype']
+ for (let a = 1; a < e.length; a += 1) {
+ const i = e[a]
+ if (null != i && !p(i)) {
+ const e = Object.keys(Object(i)).filter((e) => s.indexOf(e) < 0)
+ for (let s = 0, a = e.length; s < a; s += 1) {
+ const a = e[s],
+ r = Object.getOwnPropertyDescriptor(i, a)
+ void 0 !== r &&
+ r.enumerable &&
+ (c(t[a]) && c(i[a])
+ ? i[a].__swiper__
+ ? (t[a] = i[a])
+ : u(t[a], i[a])
+ : !c(t[a]) && c(i[a])
+ ? ((t[a] = {}), i[a].__swiper__ ? (t[a] = i[a]) : u(t[a], i[a]))
+ : (t[a] = i[a]))
+ }
+ }
+ }
+ return t
+ }
+ function m(e, t, s) {
+ e.style.setProperty(t, s)
+ }
+ function h({ swiper: e, targetPosition: t, side: s }) {
+ const a = r(),
+ i = -e.translate
+ let n,
+ l = null
+ const o = e.params.speed
+ ;(e.wrapperEl.style.scrollSnapType = 'none'),
+ a.cancelAnimationFrame(e.cssModeFrameID)
+ const d = t > i ? 'next' : 'prev',
+ c = (e, t) => ('next' === d && e >= t) || ('prev' === d && e <= t),
+ p = () => {
+ ;(n = new Date().getTime()), null === l && (l = n)
+ const r = Math.max(Math.min((n - l) / o, 1), 0),
+ d = 0.5 - Math.cos(r * Math.PI) / 2
+ let u = i + d * (t - i)
+ if ((c(u, t) && (u = t), e.wrapperEl.scrollTo({ [s]: u }), c(u, t)))
+ return (
+ (e.wrapperEl.style.overflow = 'hidden'),
+ (e.wrapperEl.style.scrollSnapType = ''),
+ setTimeout(() => {
+ ;(e.wrapperEl.style.overflow = ''),
+ e.wrapperEl.scrollTo({ [s]: u })
+ }),
+ void a.cancelAnimationFrame(e.cssModeFrameID)
+ )
+ e.cssModeFrameID = a.requestAnimationFrame(p)
+ }
+ p()
+ }
+ function f(e) {
+ return (
+ e.querySelector('.swiper-slide-transform') ||
+ (e.shadowRoot && e.shadowRoot.querySelector('.swiper-slide-transform')) ||
+ e
+ )
+ }
+ function g(e, t = '') {
+ const s = r(),
+ a = [...e.children]
+ return (
+ s.HTMLSlotElement &&
+ e instanceof HTMLSlotElement &&
+ a.push(...e.assignedElements()),
+ t ? a.filter((e) => e.matches(t)) : a
+ )
+ }
+ function v(e) {
+ try {
+ return void console.warn(e)
+ } catch (e) {}
+ }
+ function w(e, t = []) {
+ const s = document.createElement(e)
+ return s.classList.add(...(Array.isArray(t) ? t : n(t))), s
+ }
+ function b(e) {
+ const t = r(),
+ s = a(),
+ i = e.getBoundingClientRect(),
+ n = s.body,
+ l = e.clientTop || n.clientTop || 0,
+ o = e.clientLeft || n.clientLeft || 0,
+ d = e === t ? t.scrollY : e.scrollTop,
+ c = e === t ? t.scrollX : e.scrollLeft
+ return { top: i.top + d - l, left: i.left + c - o }
+ }
+ function y(e, t) {
+ return r().getComputedStyle(e, null).getPropertyValue(t)
+ }
+ function E(e) {
+ let t,
+ s = e
+ if (s) {
+ for (t = 0; null !== (s = s.previousSibling); )
+ 1 === s.nodeType && (t += 1)
+ return t
+ }
+ }
+ function x(e, t) {
+ const s = []
+ let a = e.parentElement
+ for (; a; ) t ? a.matches(t) && s.push(a) : s.push(a), (a = a.parentElement)
+ return s
+ }
+ function S(e, t) {
+ t &&
+ e.addEventListener('transitionend', function s(a) {
+ a.target === e &&
+ (t.call(e, a), e.removeEventListener('transitionend', s))
+ })
+ }
+ function T(e, t, s) {
+ const a = r()
+ return s
+ ? e['width' === t ? 'offsetWidth' : 'offsetHeight'] +
+ parseFloat(
+ a
+ .getComputedStyle(e, null)
+ .getPropertyValue('width' === t ? 'margin-right' : 'margin-top')
+ ) +
+ parseFloat(
+ a
+ .getComputedStyle(e, null)
+ .getPropertyValue('width' === t ? 'margin-left' : 'margin-bottom')
+ )
+ : e.offsetWidth
+ }
+ function M(e) {
+ return (Array.isArray(e) ? e : [e]).filter((e) => !!e)
+ }
+ function C(e) {
+ return (t) =>
+ Math.abs(t) > 0 &&
+ e.browser &&
+ e.browser.need3dFix &&
+ Math.abs(t) % 90 == 0
+ ? t + 0.001
+ : t
+ }
+ function P(e, t = '') {
+ 'undefined' != typeof trustedTypes
+ ? (e.innerHTML = trustedTypes
+ .createPolicy('html', { createHTML: (e) => e })
+ .createHTML(t))
+ : (e.innerHTML = t)
+ }
+ let L, I, z
+ function A() {
+ return (
+ L ||
+ (L = (function () {
+ const e = r(),
+ t = a()
+ return {
+ smoothScroll:
+ t.documentElement &&
+ t.documentElement.style &&
+ 'scrollBehavior' in t.documentElement.style,
+ touch: !!(
+ 'ontouchstart' in e ||
+ (e.DocumentTouch && t instanceof e.DocumentTouch)
+ ),
+ }
+ })()),
+ L
+ )
+ }
+ function $(e = {}) {
+ return (
+ I ||
+ (I = (function ({ userAgent: e } = {}) {
+ const t = A(),
+ s = r(),
+ a = s.navigator.platform,
+ i = e || s.navigator.userAgent,
+ n = { ios: !1, android: !1 },
+ l = s.screen.width,
+ o = s.screen.height,
+ d = i.match(/(Android);?[\s\/]+([\d.]+)?/)
+ let c = i.match(/(iPad)(?!\1).*OS\s([\d_]+)/)
+ const p = i.match(/(iPod)(.*OS\s([\d_]+))?/),
+ u = !c && i.match(/(iPhone\sOS|iOS)\s([\d_]+)/),
+ m = 'Win32' === a
+ let h = 'MacIntel' === a
+ return (
+ !c &&
+ h &&
+ t.touch &&
+ [
+ '1024x1366',
+ '1366x1024',
+ '834x1194',
+ '1194x834',
+ '834x1112',
+ '1112x834',
+ '768x1024',
+ '1024x768',
+ '820x1180',
+ '1180x820',
+ '810x1080',
+ '1080x810',
+ ].indexOf(`${l}x${o}`) >= 0 &&
+ ((c = i.match(/(Version)\/([\d.]+)/)),
+ c || (c = [0, 1, '13_0_0']),
+ (h = !1)),
+ d && !m && ((n.os = 'android'), (n.android = !0)),
+ (c || u || p) && ((n.os = 'ios'), (n.ios = !0)),
+ n
+ )
+ })(e)),
+ I
+ )
+ }
+ function k() {
+ return (
+ z ||
+ (z = (function () {
+ const e = r(),
+ t = $()
+ let s = !1
+ function a() {
+ const t = e.navigator.userAgent.toLowerCase()
+ return (
+ t.indexOf('safari') >= 0 &&
+ t.indexOf('chrome') < 0 &&
+ t.indexOf('android') < 0
+ )
+ }
+ if (a()) {
+ const t = String(e.navigator.userAgent)
+ if (t.includes('Version/')) {
+ const [e, a] = t
+ .split('Version/')[1]
+ .split(' ')[0]
+ .split('.')
+ .map((e) => Number(e))
+ s = e < 16 || (16 === e && a < 2)
+ }
+ }
+ const i = /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(
+ e.navigator.userAgent
+ ),
+ n = a()
+ return {
+ isSafari: s || n,
+ needPerspectiveFix: s,
+ need3dFix: n || (i && t.ios),
+ isWebView: i,
+ }
+ })()),
+ z
+ )
+ }
+ var O = {
+ on(e, t, s) {
+ const a = this
+ if (!a.eventsListeners || a.destroyed) return a
+ if ('function' != typeof t) return a
+ const i = s ? 'unshift' : 'push'
+ return (
+ e.split(' ').forEach((e) => {
+ a.eventsListeners[e] || (a.eventsListeners[e] = []),
+ a.eventsListeners[e][i](t)
+ }),
+ a
+ )
+ },
+ once(e, t, s) {
+ const a = this
+ if (!a.eventsListeners || a.destroyed) return a
+ if ('function' != typeof t) return a
+ function i(...s) {
+ a.off(e, i), i.__emitterProxy && delete i.__emitterProxy, t.apply(a, s)
+ }
+ return (i.__emitterProxy = t), a.on(e, i, s)
+ },
+ onAny(e, t) {
+ const s = this
+ if (!s.eventsListeners || s.destroyed) return s
+ if ('function' != typeof e) return s
+ const a = t ? 'unshift' : 'push'
+ return (
+ s.eventsAnyListeners.indexOf(e) < 0 && s.eventsAnyListeners[a](e), s
+ )
+ },
+ offAny(e) {
+ const t = this
+ if (!t.eventsListeners || t.destroyed) return t
+ if (!t.eventsAnyListeners) return t
+ const s = t.eventsAnyListeners.indexOf(e)
+ return s >= 0 && t.eventsAnyListeners.splice(s, 1), t
+ },
+ off(e, t) {
+ const s = this
+ return !s.eventsListeners || s.destroyed
+ ? s
+ : s.eventsListeners
+ ? (e.split(' ').forEach((e) => {
+ void 0 === t
+ ? (s.eventsListeners[e] = [])
+ : s.eventsListeners[e] &&
+ s.eventsListeners[e].forEach((a, i) => {
+ ;(a === t || (a.__emitterProxy && a.__emitterProxy === t)) &&
+ s.eventsListeners[e].splice(i, 1)
+ })
+ }),
+ s)
+ : s
+ },
+ emit(...e) {
+ const t = this
+ if (!t.eventsListeners || t.destroyed) return t
+ if (!t.eventsListeners) return t
+ let s, a, i
+ 'string' == typeof e[0] || Array.isArray(e[0])
+ ? ((s = e[0]), (a = e.slice(1, e.length)), (i = t))
+ : ((s = e[0].events), (a = e[0].data), (i = e[0].context || t)),
+ a.unshift(i)
+ return (
+ (Array.isArray(s) ? s : s.split(' ')).forEach((e) => {
+ t.eventsAnyListeners &&
+ t.eventsAnyListeners.length &&
+ t.eventsAnyListeners.forEach((t) => {
+ t.apply(i, [e, ...a])
+ }),
+ t.eventsListeners &&
+ t.eventsListeners[e] &&
+ t.eventsListeners[e].forEach((e) => {
+ e.apply(i, a)
+ })
+ }),
+ t
+ )
+ },
+ }
+ const D = (e, t, s) => {
+ t && !e.classList.contains(s)
+ ? e.classList.add(s)
+ : !t && e.classList.contains(s) && e.classList.remove(s)
+ }
+ const G = (e, t, s) => {
+ t && !e.classList.contains(s)
+ ? e.classList.add(s)
+ : !t && e.classList.contains(s) && e.classList.remove(s)
+ }
+ const X = (e, t) => {
+ if (!e || e.destroyed || !e.params) return
+ const s = t.closest(
+ e.isElement ? 'swiper-slide' : `.${e.params.slideClass}`
+ )
+ if (s) {
+ let t = s.querySelector(`.${e.params.lazyPreloaderClass}`)
+ !t &&
+ e.isElement &&
+ (s.shadowRoot
+ ? (t = s.shadowRoot.querySelector(
+ `.${e.params.lazyPreloaderClass}`
+ ))
+ : requestAnimationFrame(() => {
+ s.shadowRoot &&
+ ((t = s.shadowRoot.querySelector(
+ `.${e.params.lazyPreloaderClass}`
+ )),
+ t && t.remove())
+ })),
+ t && t.remove()
+ }
+ },
+ B = (e, t) => {
+ if (!e.slides[t]) return
+ const s = e.slides[t].querySelector('[loading="lazy"]')
+ s && s.removeAttribute('loading')
+ },
+ Y = (e) => {
+ if (!e || e.destroyed || !e.params) return
+ let t = e.params.lazyPreloadPrevNext
+ const s = e.slides.length
+ if (!s || !t || t < 0) return
+ t = Math.min(t, s)
+ const a =
+ 'auto' === e.params.slidesPerView
+ ? e.slidesPerViewDynamic()
+ : Math.ceil(e.params.slidesPerView),
+ i = e.activeIndex
+ if (e.params.grid && e.params.grid.rows > 1) {
+ const s = i,
+ r = [s - t]
+ return (
+ r.push(...Array.from({ length: t }).map((e, t) => s + a + t)),
+ void e.slides.forEach((t, s) => {
+ r.includes(t.column) && B(e, s)
+ })
+ )
+ }
+ const r = i + a - 1
+ if (e.params.rewind || e.params.loop)
+ for (let a = i - t; a <= r + t; a += 1) {
+ const t = ((a % s) + s) % s
+ ;(t < i || t > r) && B(e, t)
+ }
+ else
+ for (let a = Math.max(i - t, 0); a <= Math.min(r + t, s - 1); a += 1)
+ a !== i && (a > r || a < i) && B(e, a)
+ }
+ var H = {
+ updateSize: function () {
+ const e = this
+ let t, s
+ const a = e.el
+ ;(t =
+ void 0 !== e.params.width && null !== e.params.width
+ ? e.params.width
+ : a.clientWidth),
+ (s =
+ void 0 !== e.params.height && null !== e.params.height
+ ? e.params.height
+ : a.clientHeight),
+ (0 === t && e.isHorizontal()) ||
+ (0 === s && e.isVertical()) ||
+ ((t =
+ t -
+ parseInt(y(a, 'padding-left') || 0, 10) -
+ parseInt(y(a, 'padding-right') || 0, 10)),
+ (s =
+ s -
+ parseInt(y(a, 'padding-top') || 0, 10) -
+ parseInt(y(a, 'padding-bottom') || 0, 10)),
+ Number.isNaN(t) && (t = 0),
+ Number.isNaN(s) && (s = 0),
+ Object.assign(e, {
+ width: t,
+ height: s,
+ size: e.isHorizontal() ? t : s,
+ }))
+ },
+ updateSlides: function () {
+ const e = this
+ function t(t, s) {
+ return parseFloat(t.getPropertyValue(e.getDirectionLabel(s)) || 0)
+ }
+ const s = e.params,
+ { wrapperEl: a, slidesEl: i, rtlTranslate: r, wrongRTL: n } = e,
+ l = e.virtual && s.virtual.enabled,
+ o = l ? e.virtual.slides.length : e.slides.length,
+ d = g(i, `.${e.params.slideClass}, swiper-slide`),
+ c = l ? e.virtual.slides.length : d.length
+ let p = []
+ const u = [],
+ h = []
+ let f = s.slidesOffsetBefore
+ 'function' == typeof f && (f = s.slidesOffsetBefore.call(e))
+ let v = s.slidesOffsetAfter
+ 'function' == typeof v && (v = s.slidesOffsetAfter.call(e))
+ const w = e.snapGrid.length,
+ b = e.slidesGrid.length,
+ E = e.size - f - v
+ let x = s.spaceBetween,
+ S = -f,
+ M = 0,
+ C = 0
+ if (void 0 === E) return
+ 'string' == typeof x && x.indexOf('%') >= 0
+ ? (x = (parseFloat(x.replace('%', '')) / 100) * E)
+ : 'string' == typeof x && (x = parseFloat(x)),
+ (e.virtualSize = -x - f - v),
+ d.forEach((e) => {
+ r ? (e.style.marginLeft = '') : (e.style.marginRight = ''),
+ (e.style.marginBottom = ''),
+ (e.style.marginTop = '')
+ }),
+ s.centeredSlides &&
+ s.cssMode &&
+ (m(a, '--swiper-centered-offset-before', ''),
+ m(a, '--swiper-centered-offset-after', ''))
+ const P = s.grid && s.grid.rows > 1 && e.grid
+ let L
+ P ? e.grid.initSlides(d) : e.grid && e.grid.unsetSlides()
+ const I =
+ 'auto' === s.slidesPerView &&
+ s.breakpoints &&
+ Object.keys(s.breakpoints).filter(
+ (e) => void 0 !== s.breakpoints[e].slidesPerView
+ ).length > 0
+ for (let a = 0; a < c; a += 1) {
+ L = 0
+ const i = d[a]
+ if (
+ !i ||
+ (P && e.grid.updateSlide(a, i, d), 'none' !== y(i, 'display'))
+ ) {
+ if (l && 'auto' === s.slidesPerView)
+ s.virtual.slidesPerViewAutoSlideSize &&
+ (L = s.virtual.slidesPerViewAutoSlideSize),
+ L &&
+ i &&
+ (s.roundLengths && (L = Math.floor(L)),
+ (i.style[e.getDirectionLabel('width')] = `${L}px`))
+ else if ('auto' === s.slidesPerView) {
+ I && (i.style[e.getDirectionLabel('width')] = '')
+ const a = getComputedStyle(i),
+ r = i.style.transform,
+ n = i.style.webkitTransform
+ if (
+ (r && (i.style.transform = 'none'),
+ n && (i.style.webkitTransform = 'none'),
+ s.roundLengths)
+ )
+ L = e.isHorizontal() ? T(i, 'width', !0) : T(i, 'height', !0)
+ else {
+ const e = t(a, 'width'),
+ s = t(a, 'padding-left'),
+ r = t(a, 'padding-right'),
+ n = t(a, 'margin-left'),
+ l = t(a, 'margin-right'),
+ o = a.getPropertyValue('box-sizing')
+ if (o && 'border-box' === o) L = e + n + l
+ else {
+ const { clientWidth: t, offsetWidth: a } = i
+ L = e + s + r + n + l + (a - t)
+ }
+ }
+ r && (i.style.transform = r),
+ n && (i.style.webkitTransform = n),
+ s.roundLengths && (L = Math.floor(L))
+ } else
+ (L = (E - (s.slidesPerView - 1) * x) / s.slidesPerView),
+ s.roundLengths && (L = Math.floor(L)),
+ i && (i.style[e.getDirectionLabel('width')] = `${L}px`)
+ i && (i.swiperSlideSize = L),
+ h.push(L),
+ s.centeredSlides
+ ? ((S = S + L / 2 + M / 2 + x),
+ 0 === M && 0 !== a && (S = S - E / 2 - x),
+ 0 === a && (S = S - E / 2 - x),
+ Math.abs(S) < 0.001 && (S = 0),
+ s.roundLengths && (S = Math.floor(S)),
+ C % s.slidesPerGroup === 0 && p.push(S),
+ u.push(S))
+ : (s.roundLengths && (S = Math.floor(S)),
+ (C - Math.min(e.params.slidesPerGroupSkip, C)) %
+ e.params.slidesPerGroup ===
+ 0 && p.push(S),
+ u.push(S),
+ (S = S + L + x)),
+ (e.virtualSize += L + x),
+ (M = L),
+ (C += 1)
+ }
+ }
+ if (
+ ((e.virtualSize = Math.max(e.virtualSize, E) + v),
+ r &&
+ n &&
+ ('slide' === s.effect || 'coverflow' === s.effect) &&
+ (a.style.width = `${e.virtualSize + x}px`),
+ s.setWrapperSize &&
+ (a.style[e.getDirectionLabel('width')] = `${e.virtualSize + x}px`),
+ P && e.grid.updateWrapperSize(L, p),
+ !s.centeredSlides)
+ ) {
+ const t = []
+ for (let a = 0; a < p.length; a += 1) {
+ let i = p[a]
+ s.roundLengths && (i = Math.floor(i)),
+ p[a] <= e.virtualSize - E && t.push(i)
+ }
+ ;(p = t),
+ Math.floor(e.virtualSize - E) - Math.floor(p[p.length - 1]) > 1 &&
+ p.push(e.virtualSize - E)
+ }
+ if (l && s.loop) {
+ const t = h[0] + x
+ if (s.slidesPerGroup > 1) {
+ const a = Math.ceil(
+ (e.virtual.slidesBefore + e.virtual.slidesAfter) /
+ s.slidesPerGroup
+ ),
+ i = t * s.slidesPerGroup
+ for (let e = 0; e < a; e += 1) p.push(p[p.length - 1] + i)
+ }
+ for (
+ let a = 0;
+ a < e.virtual.slidesBefore + e.virtual.slidesAfter;
+ a += 1
+ )
+ 1 === s.slidesPerGroup && p.push(p[p.length - 1] + t),
+ u.push(u[u.length - 1] + t),
+ (e.virtualSize += t)
+ }
+ if ((0 === p.length && (p = [0]), 0 !== x)) {
+ const t =
+ e.isHorizontal() && r
+ ? 'marginLeft'
+ : e.getDirectionLabel('marginRight')
+ d.filter(
+ (e, t) => !(s.cssMode && !s.loop) || t !== d.length - 1
+ ).forEach((e) => {
+ e.style[t] = `${x}px`
+ })
+ }
+ if (s.centeredSlides && s.centeredSlidesBounds) {
+ let e = 0
+ h.forEach((t) => {
+ e += t + (x || 0)
+ }),
+ (e -= x)
+ const t = e > E ? e - E : 0
+ p = p.map((e) => (e <= 0 ? -f : e > t ? t + v : e))
+ }
+ if (s.centerInsufficientSlides) {
+ let e = 0
+ h.forEach((t) => {
+ e += t + (x || 0)
+ }),
+ (e -= x)
+ const t = (f || 0) + (v || 0)
+ if (e + t < E) {
+ const s = (E - e - t) / 2
+ p.forEach((e, t) => {
+ p[t] = e - s
+ }),
+ u.forEach((e, t) => {
+ u[t] = e + s
+ })
+ }
+ }
+ if (
+ (Object.assign(e, {
+ slides: d,
+ snapGrid: p,
+ slidesGrid: u,
+ slidesSizesGrid: h,
+ }),
+ s.centeredSlides && s.cssMode && !s.centeredSlidesBounds)
+ ) {
+ m(a, '--swiper-centered-offset-before', -p[0] + 'px'),
+ m(
+ a,
+ '--swiper-centered-offset-after',
+ e.size / 2 - h[h.length - 1] / 2 + 'px'
+ )
+ const t = -e.snapGrid[0],
+ s = -e.slidesGrid[0]
+ ;(e.snapGrid = e.snapGrid.map((e) => e + t)),
+ (e.slidesGrid = e.slidesGrid.map((e) => e + s))
+ }
+ if (
+ (c !== o && e.emit('slidesLengthChange'),
+ p.length !== w &&
+ (e.params.watchOverflow && e.checkOverflow(),
+ e.emit('snapGridLengthChange')),
+ u.length !== b && e.emit('slidesGridLengthChange'),
+ s.watchSlidesProgress && e.updateSlidesOffset(),
+ e.emit('slidesUpdated'),
+ !(l || s.cssMode || ('slide' !== s.effect && 'fade' !== s.effect)))
+ ) {
+ const t = `${s.containerModifierClass}backface-hidden`,
+ a = e.el.classList.contains(t)
+ c <= s.maxBackfaceHiddenSlides
+ ? a || e.el.classList.add(t)
+ : a && e.el.classList.remove(t)
+ }
+ },
+ updateAutoHeight: function (e) {
+ const t = this,
+ s = [],
+ a = t.virtual && t.params.virtual.enabled
+ let i,
+ r = 0
+ 'number' == typeof e
+ ? t.setTransition(e)
+ : !0 === e && t.setTransition(t.params.speed)
+ const n = (e) => (a ? t.slides[t.getSlideIndexByData(e)] : t.slides[e])
+ if ('auto' !== t.params.slidesPerView && t.params.slidesPerView > 1)
+ if (t.params.centeredSlides)
+ (t.visibleSlides || []).forEach((e) => {
+ s.push(e)
+ })
+ else
+ for (i = 0; i < Math.ceil(t.params.slidesPerView); i += 1) {
+ const e = t.activeIndex + i
+ if (e > t.slides.length && !a) break
+ s.push(n(e))
+ }
+ else s.push(n(t.activeIndex))
+ for (i = 0; i < s.length; i += 1)
+ if (void 0 !== s[i]) {
+ const e = s[i].offsetHeight
+ r = e > r ? e : r
+ }
+ ;(r || 0 === r) && (t.wrapperEl.style.height = `${r}px`)
+ },
+ updateSlidesOffset: function () {
+ const e = this,
+ t = e.slides,
+ s = e.isElement
+ ? e.isHorizontal()
+ ? e.wrapperEl.offsetLeft
+ : e.wrapperEl.offsetTop
+ : 0
+ for (let a = 0; a < t.length; a += 1)
+ t[a].swiperSlideOffset =
+ (e.isHorizontal() ? t[a].offsetLeft : t[a].offsetTop) -
+ s -
+ e.cssOverflowAdjustment()
+ },
+ updateSlidesProgress: function (e = (this && this.translate) || 0) {
+ const t = this,
+ s = t.params,
+ { slides: a, rtlTranslate: i, snapGrid: r } = t
+ if (0 === a.length) return
+ void 0 === a[0].swiperSlideOffset && t.updateSlidesOffset()
+ let n = -e
+ i && (n = e), (t.visibleSlidesIndexes = []), (t.visibleSlides = [])
+ let l = s.spaceBetween
+ 'string' == typeof l && l.indexOf('%') >= 0
+ ? (l = (parseFloat(l.replace('%', '')) / 100) * t.size)
+ : 'string' == typeof l && (l = parseFloat(l))
+ for (let e = 0; e < a.length; e += 1) {
+ const o = a[e]
+ let d = o.swiperSlideOffset
+ s.cssMode && s.centeredSlides && (d -= a[0].swiperSlideOffset)
+ const c =
+ (n + (s.centeredSlides ? t.minTranslate() : 0) - d) /
+ (o.swiperSlideSize + l),
+ p =
+ (n - r[0] + (s.centeredSlides ? t.minTranslate() : 0) - d) /
+ (o.swiperSlideSize + l),
+ u = -(n - d),
+ m = u + t.slidesSizesGrid[e],
+ h = u >= 0 && u <= t.size - t.slidesSizesGrid[e],
+ f =
+ (u >= 0 && u < t.size - 1) ||
+ (m > 1 && m <= t.size) ||
+ (u <= 0 && m >= t.size)
+ f && (t.visibleSlides.push(o), t.visibleSlidesIndexes.push(e)),
+ D(o, f, s.slideVisibleClass),
+ D(o, h, s.slideFullyVisibleClass),
+ (o.progress = i ? -c : c),
+ (o.originalProgress = i ? -p : p)
+ }
+ },
+ updateProgress: function (e) {
+ const t = this
+ if (void 0 === e) {
+ const s = t.rtlTranslate ? -1 : 1
+ e = (t && t.translate && t.translate * s) || 0
+ }
+ const s = t.params,
+ a = t.maxTranslate() - t.minTranslate()
+ let { progress: i, isBeginning: r, isEnd: n, progressLoop: l } = t
+ const o = r,
+ d = n
+ if (0 === a) (i = 0), (r = !0), (n = !0)
+ else {
+ i = (e - t.minTranslate()) / a
+ const s = Math.abs(e - t.minTranslate()) < 1,
+ l = Math.abs(e - t.maxTranslate()) < 1
+ ;(r = s || i <= 0), (n = l || i >= 1), s && (i = 0), l && (i = 1)
+ }
+ if (s.loop) {
+ const s = t.getSlideIndexByData(0),
+ a = t.getSlideIndexByData(t.slides.length - 1),
+ i = t.slidesGrid[s],
+ r = t.slidesGrid[a],
+ n = t.slidesGrid[t.slidesGrid.length - 1],
+ o = Math.abs(e)
+ ;(l = o >= i ? (o - i) / n : (o + n - r) / n), l > 1 && (l -= 1)
+ }
+ Object.assign(t, {
+ progress: i,
+ progressLoop: l,
+ isBeginning: r,
+ isEnd: n,
+ }),
+ (s.watchSlidesProgress || (s.centeredSlides && s.autoHeight)) &&
+ t.updateSlidesProgress(e),
+ r && !o && t.emit('reachBeginning toEdge'),
+ n && !d && t.emit('reachEnd toEdge'),
+ ((o && !r) || (d && !n)) && t.emit('fromEdge'),
+ t.emit('progress', i)
+ },
+ updateSlidesClasses: function () {
+ const e = this,
+ { slides: t, params: s, slidesEl: a, activeIndex: i } = e,
+ r = e.virtual && s.virtual.enabled,
+ n = e.grid && s.grid && s.grid.rows > 1,
+ l = (e) => g(a, `.${s.slideClass}${e}, swiper-slide${e}`)[0]
+ let o, d, c
+ if (r)
+ if (s.loop) {
+ let t = i - e.virtual.slidesBefore
+ t < 0 && (t = e.virtual.slides.length + t),
+ t >= e.virtual.slides.length && (t -= e.virtual.slides.length),
+ (o = l(`[data-swiper-slide-index="${t}"]`))
+ } else o = l(`[data-swiper-slide-index="${i}"]`)
+ else
+ n
+ ? ((o = t.find((e) => e.column === i)),
+ (c = t.find((e) => e.column === i + 1)),
+ (d = t.find((e) => e.column === i - 1)))
+ : (o = t[i])
+ o &&
+ (n ||
+ ((c = (function (e, t) {
+ const s = []
+ for (; e.nextElementSibling; ) {
+ const a = e.nextElementSibling
+ t ? a.matches(t) && s.push(a) : s.push(a), (e = a)
+ }
+ return s
+ })(o, `.${s.slideClass}, swiper-slide`)[0]),
+ s.loop && !c && (c = t[0]),
+ (d = (function (e, t) {
+ const s = []
+ for (; e.previousElementSibling; ) {
+ const a = e.previousElementSibling
+ t ? a.matches(t) && s.push(a) : s.push(a), (e = a)
+ }
+ return s
+ })(o, `.${s.slideClass}, swiper-slide`)[0]),
+ s.loop && 0 === !d && (d = t[t.length - 1]))),
+ t.forEach((e) => {
+ G(e, e === o, s.slideActiveClass),
+ G(e, e === c, s.slideNextClass),
+ G(e, e === d, s.slidePrevClass)
+ }),
+ e.emitSlidesClasses()
+ },
+ updateActiveIndex: function (e) {
+ const t = this,
+ s = t.rtlTranslate ? t.translate : -t.translate,
+ {
+ snapGrid: a,
+ params: i,
+ activeIndex: r,
+ realIndex: n,
+ snapIndex: l,
+ } = t
+ let o,
+ d = e
+ const c = (e) => {
+ let s = e - t.virtual.slidesBefore
+ return (
+ s < 0 && (s = t.virtual.slides.length + s),
+ s >= t.virtual.slides.length && (s -= t.virtual.slides.length),
+ s
+ )
+ }
+ if (
+ (void 0 === d &&
+ (d = (function (e) {
+ const { slidesGrid: t, params: s } = e,
+ a = e.rtlTranslate ? e.translate : -e.translate
+ let i
+ for (let e = 0; e < t.length; e += 1)
+ void 0 !== t[e + 1]
+ ? a >= t[e] && a < t[e + 1] - (t[e + 1] - t[e]) / 2
+ ? (i = e)
+ : a >= t[e] && a < t[e + 1] && (i = e + 1)
+ : a >= t[e] && (i = e)
+ return (
+ s.normalizeSlideIndex && (i < 0 || void 0 === i) && (i = 0), i
+ )
+ })(t)),
+ a.indexOf(s) >= 0)
+ )
+ o = a.indexOf(s)
+ else {
+ const e = Math.min(i.slidesPerGroupSkip, d)
+ o = e + Math.floor((d - e) / i.slidesPerGroup)
+ }
+ if ((o >= a.length && (o = a.length - 1), d === r && !t.params.loop))
+ return void (o !== l && ((t.snapIndex = o), t.emit('snapIndexChange')))
+ if (d === r && t.params.loop && t.virtual && t.params.virtual.enabled)
+ return void (t.realIndex = c(d))
+ const p = t.grid && i.grid && i.grid.rows > 1
+ let u
+ if (t.virtual && i.virtual.enabled && i.loop) u = c(d)
+ else if (p) {
+ const e = t.slides.find((e) => e.column === d)
+ let s = parseInt(e.getAttribute('data-swiper-slide-index'), 10)
+ Number.isNaN(s) && (s = Math.max(t.slides.indexOf(e), 0)),
+ (u = Math.floor(s / i.grid.rows))
+ } else if (t.slides[d]) {
+ const e = t.slides[d].getAttribute('data-swiper-slide-index')
+ u = e ? parseInt(e, 10) : d
+ } else u = d
+ Object.assign(t, {
+ previousSnapIndex: l,
+ snapIndex: o,
+ previousRealIndex: n,
+ realIndex: u,
+ previousIndex: r,
+ activeIndex: d,
+ }),
+ t.initialized && Y(t),
+ t.emit('activeIndexChange'),
+ t.emit('snapIndexChange'),
+ (t.initialized || t.params.runCallbacksOnInit) &&
+ (n !== u && t.emit('realIndexChange'), t.emit('slideChange'))
+ },
+ updateClickedSlide: function (e, t) {
+ const s = this,
+ a = s.params
+ let i = e.closest(`.${a.slideClass}, swiper-slide`)
+ !i &&
+ s.isElement &&
+ t &&
+ t.length > 1 &&
+ t.includes(e) &&
+ [...t.slice(t.indexOf(e) + 1, t.length)].forEach((e) => {
+ !i &&
+ e.matches &&
+ e.matches(`.${a.slideClass}, swiper-slide`) &&
+ (i = e)
+ })
+ let r,
+ n = !1
+ if (i)
+ for (let e = 0; e < s.slides.length; e += 1)
+ if (s.slides[e] === i) {
+ ;(n = !0), (r = e)
+ break
+ }
+ if (!i || !n)
+ return (s.clickedSlide = void 0), void (s.clickedIndex = void 0)
+ ;(s.clickedSlide = i),
+ s.virtual && s.params.virtual.enabled
+ ? (s.clickedIndex = parseInt(
+ i.getAttribute('data-swiper-slide-index'),
+ 10
+ ))
+ : (s.clickedIndex = r),
+ a.slideToClickedSlide &&
+ void 0 !== s.clickedIndex &&
+ s.clickedIndex !== s.activeIndex &&
+ s.slideToClickedSlide()
+ },
+ }
+ var N = {
+ getTranslate: function (e = this.isHorizontal() ? 'x' : 'y') {
+ const { params: t, rtlTranslate: s, translate: a, wrapperEl: i } = this
+ if (t.virtualTranslate) return s ? -a : a
+ if (t.cssMode) return a
+ let r = d(i, e)
+ return (r += this.cssOverflowAdjustment()), s && (r = -r), r || 0
+ },
+ setTranslate: function (e, t) {
+ const s = this,
+ { rtlTranslate: a, params: i, wrapperEl: r, progress: n } = s
+ let l,
+ o = 0,
+ d = 0
+ s.isHorizontal() ? (o = a ? -e : e) : (d = e),
+ i.roundLengths && ((o = Math.floor(o)), (d = Math.floor(d))),
+ (s.previousTranslate = s.translate),
+ (s.translate = s.isHorizontal() ? o : d),
+ i.cssMode
+ ? (r[s.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = s.isHorizontal()
+ ? -o
+ : -d)
+ : i.virtualTranslate ||
+ (s.isHorizontal()
+ ? (o -= s.cssOverflowAdjustment())
+ : (d -= s.cssOverflowAdjustment()),
+ (r.style.transform = `translate3d(${o}px, ${d}px, 0px)`))
+ const c = s.maxTranslate() - s.minTranslate()
+ ;(l = 0 === c ? 0 : (e - s.minTranslate()) / c),
+ l !== n && s.updateProgress(e),
+ s.emit('setTranslate', s.translate, t)
+ },
+ minTranslate: function () {
+ return -this.snapGrid[0]
+ },
+ maxTranslate: function () {
+ return -this.snapGrid[this.snapGrid.length - 1]
+ },
+ translateTo: function (e = 0, t = this.params.speed, s = !0, a = !0, i) {
+ const r = this,
+ { params: n, wrapperEl: l } = r
+ if (r.animating && n.preventInteractionOnTransition) return !1
+ const o = r.minTranslate(),
+ d = r.maxTranslate()
+ let c
+ if (
+ ((c = a && e > o ? o : a && e < d ? d : e),
+ r.updateProgress(c),
+ n.cssMode)
+ ) {
+ const e = r.isHorizontal()
+ if (0 === t) l[e ? 'scrollLeft' : 'scrollTop'] = -c
+ else {
+ if (!r.support.smoothScroll)
+ return (
+ h({ swiper: r, targetPosition: -c, side: e ? 'left' : 'top' }), !0
+ )
+ l.scrollTo({ [e ? 'left' : 'top']: -c, behavior: 'smooth' })
+ }
+ return !0
+ }
+ return (
+ 0 === t
+ ? (r.setTransition(0),
+ r.setTranslate(c),
+ s &&
+ (r.emit('beforeTransitionStart', t, i), r.emit('transitionEnd')))
+ : (r.setTransition(t),
+ r.setTranslate(c),
+ s &&
+ (r.emit('beforeTransitionStart', t, i),
+ r.emit('transitionStart')),
+ r.animating ||
+ ((r.animating = !0),
+ r.onTranslateToWrapperTransitionEnd ||
+ (r.onTranslateToWrapperTransitionEnd = function (e) {
+ r &&
+ !r.destroyed &&
+ e.target === this &&
+ (r.wrapperEl.removeEventListener(
+ 'transitionend',
+ r.onTranslateToWrapperTransitionEnd
+ ),
+ (r.onTranslateToWrapperTransitionEnd = null),
+ delete r.onTranslateToWrapperTransitionEnd,
+ (r.animating = !1),
+ s && r.emit('transitionEnd'))
+ }),
+ r.wrapperEl.addEventListener(
+ 'transitionend',
+ r.onTranslateToWrapperTransitionEnd
+ ))),
+ !0
+ )
+ },
+ }
+ function R({ swiper: e, runCallbacks: t, direction: s, step: a }) {
+ const { activeIndex: i, previousIndex: r } = e
+ let n = s
+ n || (n = i > r ? 'next' : i < r ? 'prev' : 'reset'),
+ e.emit(`transition${a}`),
+ t && 'reset' === n
+ ? e.emit(`slideResetTransition${a}`)
+ : t &&
+ i !== r &&
+ (e.emit(`slideChangeTransition${a}`),
+ 'next' === n
+ ? e.emit(`slideNextTransition${a}`)
+ : e.emit(`slidePrevTransition${a}`))
+ }
+ var V = {
+ slideTo: function (e = 0, t, s = !0, a, i) {
+ 'string' == typeof e && (e = parseInt(e, 10))
+ const r = this
+ let n = e
+ n < 0 && (n = 0)
+ const {
+ params: l,
+ snapGrid: o,
+ slidesGrid: d,
+ previousIndex: c,
+ activeIndex: p,
+ rtlTranslate: u,
+ wrapperEl: m,
+ enabled: f,
+ } = r
+ if (
+ (!f && !a && !i) ||
+ r.destroyed ||
+ (r.animating && l.preventInteractionOnTransition)
+ )
+ return !1
+ void 0 === t && (t = r.params.speed)
+ const g = Math.min(r.params.slidesPerGroupSkip, n)
+ let v = g + Math.floor((n - g) / r.params.slidesPerGroup)
+ v >= o.length && (v = o.length - 1)
+ const w = -o[v]
+ if (l.normalizeSlideIndex)
+ for (let e = 0; e < d.length; e += 1) {
+ const t = -Math.floor(100 * w),
+ s = Math.floor(100 * d[e]),
+ a = Math.floor(100 * d[e + 1])
+ void 0 !== d[e + 1]
+ ? t >= s && t < a - (a - s) / 2
+ ? (n = e)
+ : t >= s && t < a && (n = e + 1)
+ : t >= s && (n = e)
+ }
+ if (r.initialized && n !== p) {
+ if (
+ !r.allowSlideNext &&
+ (u
+ ? w > r.translate && w > r.minTranslate()
+ : w < r.translate && w < r.minTranslate())
+ )
+ return !1
+ if (
+ !r.allowSlidePrev &&
+ w > r.translate &&
+ w > r.maxTranslate() &&
+ (p || 0) !== n
+ )
+ return !1
+ }
+ let b
+ n !== (c || 0) && s && r.emit('beforeSlideChangeStart'),
+ r.updateProgress(w),
+ (b = n > p ? 'next' : n < p ? 'prev' : 'reset')
+ const y = r.virtual && r.params.virtual.enabled
+ if (!(y && i) && ((u && -w === r.translate) || (!u && w === r.translate)))
+ return (
+ r.updateActiveIndex(n),
+ l.autoHeight && r.updateAutoHeight(),
+ r.updateSlidesClasses(),
+ 'slide' !== l.effect && r.setTranslate(w),
+ 'reset' !== b && (r.transitionStart(s, b), r.transitionEnd(s, b)),
+ !1
+ )
+ if (l.cssMode) {
+ const e = r.isHorizontal(),
+ s = u ? w : -w
+ if (0 === t)
+ y &&
+ ((r.wrapperEl.style.scrollSnapType = 'none'),
+ (r._immediateVirtual = !0)),
+ y && !r._cssModeVirtualInitialSet && r.params.initialSlide > 0
+ ? ((r._cssModeVirtualInitialSet = !0),
+ requestAnimationFrame(() => {
+ m[e ? 'scrollLeft' : 'scrollTop'] = s
+ }))
+ : (m[e ? 'scrollLeft' : 'scrollTop'] = s),
+ y &&
+ requestAnimationFrame(() => {
+ ;(r.wrapperEl.style.scrollSnapType = ''),
+ (r._immediateVirtual = !1)
+ })
+ else {
+ if (!r.support.smoothScroll)
+ return (
+ h({ swiper: r, targetPosition: s, side: e ? 'left' : 'top' }), !0
+ )
+ m.scrollTo({ [e ? 'left' : 'top']: s, behavior: 'smooth' })
+ }
+ return !0
+ }
+ const E = k().isSafari
+ return (
+ y && !i && E && r.isElement && r.virtual.update(!1, !1, n),
+ r.setTransition(t),
+ r.setTranslate(w),
+ r.updateActiveIndex(n),
+ r.updateSlidesClasses(),
+ r.emit('beforeTransitionStart', t, a),
+ r.transitionStart(s, b),
+ 0 === t
+ ? r.transitionEnd(s, b)
+ : r.animating ||
+ ((r.animating = !0),
+ r.onSlideToWrapperTransitionEnd ||
+ (r.onSlideToWrapperTransitionEnd = function (e) {
+ r &&
+ !r.destroyed &&
+ e.target === this &&
+ (r.wrapperEl.removeEventListener(
+ 'transitionend',
+ r.onSlideToWrapperTransitionEnd
+ ),
+ (r.onSlideToWrapperTransitionEnd = null),
+ delete r.onSlideToWrapperTransitionEnd,
+ r.transitionEnd(s, b))
+ }),
+ r.wrapperEl.addEventListener(
+ 'transitionend',
+ r.onSlideToWrapperTransitionEnd
+ )),
+ !0
+ )
+ },
+ slideToLoop: function (e = 0, t, s = !0, a) {
+ if ('string' == typeof e) {
+ e = parseInt(e, 10)
+ }
+ const i = this
+ if (i.destroyed) return
+ void 0 === t && (t = i.params.speed)
+ const r = i.grid && i.params.grid && i.params.grid.rows > 1
+ let n = e
+ if (i.params.loop)
+ if (i.virtual && i.params.virtual.enabled) n += i.virtual.slidesBefore
+ else {
+ let e
+ if (r) {
+ const t = n * i.params.grid.rows
+ e = i.slides.find(
+ (e) => 1 * e.getAttribute('data-swiper-slide-index') === t
+ ).column
+ } else e = i.getSlideIndexByData(n)
+ const t = r
+ ? Math.ceil(i.slides.length / i.params.grid.rows)
+ : i.slides.length,
+ {
+ centeredSlides: s,
+ slidesOffsetBefore: l,
+ slidesOffsetAfter: o,
+ } = i.params,
+ d = s || !!l || !!o
+ let c = i.params.slidesPerView
+ 'auto' === c
+ ? (c = i.slidesPerViewDynamic())
+ : ((c = Math.ceil(parseFloat(i.params.slidesPerView, 10))),
+ d && c % 2 == 0 && (c += 1))
+ let p = t - e < c
+ if (
+ (d && (p = p || e < Math.ceil(c / 2)),
+ a && d && 'auto' !== i.params.slidesPerView && !r && (p = !1),
+ p)
+ ) {
+ const s = d
+ ? e < i.activeIndex
+ ? 'prev'
+ : 'next'
+ : e - i.activeIndex - 1 < i.params.slidesPerView
+ ? 'next'
+ : 'prev'
+ i.loopFix({
+ direction: s,
+ slideTo: !0,
+ activeSlideIndex: 'next' === s ? e + 1 : e - t + 1,
+ slideRealIndex: 'next' === s ? i.realIndex : void 0,
+ })
+ }
+ if (r) {
+ const e = n * i.params.grid.rows
+ n = i.slides.find(
+ (t) => 1 * t.getAttribute('data-swiper-slide-index') === e
+ ).column
+ } else n = i.getSlideIndexByData(n)
+ }
+ return (
+ requestAnimationFrame(() => {
+ i.slideTo(n, t, s, a)
+ }),
+ i
+ )
+ },
+ slideNext: function (e, t = !0, s) {
+ const a = this,
+ { enabled: i, params: r, animating: n } = a
+ if (!i || a.destroyed) return a
+ void 0 === e && (e = a.params.speed)
+ let l = r.slidesPerGroup
+ 'auto' === r.slidesPerView &&
+ 1 === r.slidesPerGroup &&
+ r.slidesPerGroupAuto &&
+ (l = Math.max(a.slidesPerViewDynamic('current', !0), 1))
+ const o = a.activeIndex < r.slidesPerGroupSkip ? 1 : l,
+ d = a.virtual && r.virtual.enabled
+ if (r.loop) {
+ if (n && !d && r.loopPreventsSliding) return !1
+ if (
+ (a.loopFix({ direction: 'next' }),
+ (a._clientLeft = a.wrapperEl.clientLeft),
+ a.activeIndex === a.slides.length - 1 && r.cssMode)
+ )
+ return (
+ requestAnimationFrame(() => {
+ a.slideTo(a.activeIndex + o, e, t, s)
+ }),
+ !0
+ )
+ }
+ return r.rewind && a.isEnd
+ ? a.slideTo(0, e, t, s)
+ : a.slideTo(a.activeIndex + o, e, t, s)
+ },
+ slidePrev: function (e, t = !0, s) {
+ const a = this,
+ {
+ params: i,
+ snapGrid: r,
+ slidesGrid: n,
+ rtlTranslate: l,
+ enabled: o,
+ animating: d,
+ } = a
+ if (!o || a.destroyed) return a
+ void 0 === e && (e = a.params.speed)
+ const c = a.virtual && i.virtual.enabled
+ if (i.loop) {
+ if (d && !c && i.loopPreventsSliding) return !1
+ a.loopFix({ direction: 'prev' }),
+ (a._clientLeft = a.wrapperEl.clientLeft)
+ }
+ function p(e) {
+ return e < 0 ? -Math.floor(Math.abs(e)) : Math.floor(e)
+ }
+ const u = p(l ? a.translate : -a.translate),
+ m = r.map((e) => p(e)),
+ h = i.freeMode && i.freeMode.enabled
+ let f = r[m.indexOf(u) - 1]
+ if (void 0 === f && (i.cssMode || h)) {
+ let e
+ r.forEach((t, s) => {
+ u >= t && (e = s)
+ }),
+ void 0 !== e && (f = h ? r[e] : r[e > 0 ? e - 1 : e])
+ }
+ let g = 0
+ if (
+ (void 0 !== f &&
+ ((g = n.indexOf(f)),
+ g < 0 && (g = a.activeIndex - 1),
+ 'auto' === i.slidesPerView &&
+ 1 === i.slidesPerGroup &&
+ i.slidesPerGroupAuto &&
+ ((g = g - a.slidesPerViewDynamic('previous', !0) + 1),
+ (g = Math.max(g, 0)))),
+ i.rewind && a.isBeginning)
+ ) {
+ const i =
+ a.params.virtual && a.params.virtual.enabled && a.virtual
+ ? a.virtual.slides.length - 1
+ : a.slides.length - 1
+ return a.slideTo(i, e, t, s)
+ }
+ return i.loop && 0 === a.activeIndex && i.cssMode
+ ? (requestAnimationFrame(() => {
+ a.slideTo(g, e, t, s)
+ }),
+ !0)
+ : a.slideTo(g, e, t, s)
+ },
+ slideReset: function (e, t = !0, s) {
+ const a = this
+ if (!a.destroyed)
+ return (
+ void 0 === e && (e = a.params.speed),
+ a.slideTo(a.activeIndex, e, t, s)
+ )
+ },
+ slideToClosest: function (e, t = !0, s, a = 0.5) {
+ const i = this
+ if (i.destroyed) return
+ void 0 === e && (e = i.params.speed)
+ let r = i.activeIndex
+ const n = Math.min(i.params.slidesPerGroupSkip, r),
+ l = n + Math.floor((r - n) / i.params.slidesPerGroup),
+ o = i.rtlTranslate ? i.translate : -i.translate
+ if (o >= i.snapGrid[l]) {
+ const e = i.snapGrid[l]
+ o - e > (i.snapGrid[l + 1] - e) * a && (r += i.params.slidesPerGroup)
+ } else {
+ const e = i.snapGrid[l - 1]
+ o - e <= (i.snapGrid[l] - e) * a && (r -= i.params.slidesPerGroup)
+ }
+ return (
+ (r = Math.max(r, 0)),
+ (r = Math.min(r, i.slidesGrid.length - 1)),
+ i.slideTo(r, e, t, s)
+ )
+ },
+ slideToClickedSlide: function () {
+ const e = this
+ if (e.destroyed) return
+ const { params: t, slidesEl: s } = e,
+ a =
+ 'auto' === t.slidesPerView
+ ? e.slidesPerViewDynamic()
+ : t.slidesPerView
+ let i,
+ r = e.getSlideIndexWhenGrid(e.clickedIndex)
+ const n = e.isElement ? 'swiper-slide' : `.${t.slideClass}`,
+ o = e.grid && e.params.grid && e.params.grid.rows > 1
+ if (t.loop) {
+ if (e.animating) return
+ ;(i = parseInt(
+ e.clickedSlide.getAttribute('data-swiper-slide-index'),
+ 10
+ )),
+ t.centeredSlides
+ ? e.slideToLoop(i)
+ : r >
+ (o
+ ? (e.slides.length - a) / 2 - (e.params.grid.rows - 1)
+ : e.slides.length - a)
+ ? (e.loopFix(),
+ (r = e.getSlideIndex(
+ g(s, `${n}[data-swiper-slide-index="${i}"]`)[0]
+ )),
+ l(() => {
+ e.slideTo(r)
+ }))
+ : e.slideTo(r)
+ } else e.slideTo(r)
+ },
+ }
+ var q = {
+ loopCreate: function (e, t) {
+ const s = this,
+ { params: a, slidesEl: i } = s
+ if (!a.loop || (s.virtual && s.params.virtual.enabled)) return
+ const r = () => {
+ g(i, `.${a.slideClass}, swiper-slide`).forEach((e, t) => {
+ e.setAttribute('data-swiper-slide-index', t)
+ })
+ },
+ n = s.grid && a.grid && a.grid.rows > 1
+ a.loopAddBlankSlides &&
+ (a.slidesPerGroup > 1 || n) &&
+ (() => {
+ const e = g(i, `.${a.slideBlankClass}`)
+ e.forEach((e) => {
+ e.remove()
+ }),
+ e.length > 0 && (s.recalcSlides(), s.updateSlides())
+ })()
+ const l = a.slidesPerGroup * (n ? a.grid.rows : 1),
+ o = s.slides.length % l !== 0,
+ d = n && s.slides.length % a.grid.rows !== 0,
+ c = (e) => {
+ for (let t = 0; t < e; t += 1) {
+ const e = s.isElement
+ ? w('swiper-slide', [a.slideBlankClass])
+ : w('div', [a.slideClass, a.slideBlankClass])
+ s.slidesEl.append(e)
+ }
+ }
+ if (o) {
+ if (a.loopAddBlankSlides) {
+ c(l - (s.slides.length % l)), s.recalcSlides(), s.updateSlides()
+ } else
+ v(
+ 'Swiper Loop Warning: The number of slides is not even to slidesPerGroup, loop mode may not function properly. You need to add more slides (or make duplicates, or empty slides)'
+ )
+ r()
+ } else if (d) {
+ if (a.loopAddBlankSlides) {
+ c(a.grid.rows - (s.slides.length % a.grid.rows)),
+ s.recalcSlides(),
+ s.updateSlides()
+ } else
+ v(
+ 'Swiper Loop Warning: The number of slides is not even to grid.rows, loop mode may not function properly. You need to add more slides (or make duplicates, or empty slides)'
+ )
+ r()
+ } else r()
+ const p =
+ a.centeredSlides || !!a.slidesOffsetBefore || !!a.slidesOffsetAfter
+ s.loopFix({
+ slideRealIndex: e,
+ direction: p ? void 0 : 'next',
+ initial: t,
+ })
+ },
+ loopFix: function ({
+ slideRealIndex: e,
+ slideTo: t = !0,
+ direction: s,
+ setTranslate: a,
+ activeSlideIndex: i,
+ initial: r,
+ byController: n,
+ byMousewheel: l,
+ } = {}) {
+ const o = this
+ if (!o.params.loop) return
+ o.emit('beforeLoopFix')
+ const {
+ slides: d,
+ allowSlidePrev: c,
+ allowSlideNext: p,
+ slidesEl: u,
+ params: m,
+ } = o,
+ {
+ centeredSlides: h,
+ slidesOffsetBefore: f,
+ slidesOffsetAfter: g,
+ initialSlide: w,
+ } = m,
+ b = h || !!f || !!g
+ if (
+ ((o.allowSlidePrev = !0),
+ (o.allowSlideNext = !0),
+ o.virtual && m.virtual.enabled)
+ )
+ return (
+ t &&
+ (b || 0 !== o.snapIndex
+ ? b && o.snapIndex < m.slidesPerView
+ ? o.slideTo(o.virtual.slides.length + o.snapIndex, 0, !1, !0)
+ : o.snapIndex === o.snapGrid.length - 1 &&
+ o.slideTo(o.virtual.slidesBefore, 0, !1, !0)
+ : o.slideTo(o.virtual.slides.length, 0, !1, !0)),
+ (o.allowSlidePrev = c),
+ (o.allowSlideNext = p),
+ void o.emit('loopFix')
+ )
+ let y = m.slidesPerView
+ 'auto' === y
+ ? (y = o.slidesPerViewDynamic())
+ : ((y = Math.ceil(parseFloat(m.slidesPerView, 10))),
+ b && y % 2 == 0 && (y += 1))
+ const E = m.slidesPerGroupAuto ? y : m.slidesPerGroup
+ let x = b ? Math.max(E, Math.ceil(y / 2)) : E
+ x % E !== 0 && (x += E - (x % E)),
+ (x += m.loopAdditionalSlides),
+ (o.loopedSlides = x)
+ const S = o.grid && m.grid && m.grid.rows > 1
+ d.length < y + x || ('cards' === o.params.effect && d.length < y + 2 * x)
+ ? v(
+ 'Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled or not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters'
+ )
+ : S &&
+ 'row' === m.grid.fill &&
+ v(
+ 'Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`'
+ )
+ const T = [],
+ M = [],
+ C = S ? Math.ceil(d.length / m.grid.rows) : d.length,
+ P = r && C - w < y && !b
+ let L = P ? w : o.activeIndex
+ void 0 === i
+ ? (i = o.getSlideIndex(
+ d.find((e) => e.classList.contains(m.slideActiveClass))
+ ))
+ : (L = i)
+ const I = 'next' === s || !s,
+ z = 'prev' === s || !s
+ let A = 0,
+ $ = 0
+ const k = (S ? d[i].column : i) + (b && void 0 === a ? -y / 2 + 0.5 : 0)
+ if (k < x) {
+ A = Math.max(x - k, E)
+ for (let e = 0; e < x - k; e += 1) {
+ const t = e - Math.floor(e / C) * C
+ if (S) {
+ const e = C - t - 1
+ for (let t = d.length - 1; t >= 0; t -= 1)
+ d[t].column === e && T.push(t)
+ } else T.push(C - t - 1)
+ }
+ } else if (k + y > C - x) {
+ ;($ = Math.max(k - (C - 2 * x), E)),
+ P && ($ = Math.max($, y - C + w + 1))
+ for (let e = 0; e < $; e += 1) {
+ const t = e - Math.floor(e / C) * C
+ S
+ ? d.forEach((e, s) => {
+ e.column === t && M.push(s)
+ })
+ : M.push(t)
+ }
+ }
+ if (
+ ((o.__preventObserver__ = !0),
+ requestAnimationFrame(() => {
+ o.__preventObserver__ = !1
+ }),
+ 'cards' === o.params.effect &&
+ d.length < y + 2 * x &&
+ (M.includes(i) && M.splice(M.indexOf(i), 1),
+ T.includes(i) && T.splice(T.indexOf(i), 1)),
+ z &&
+ T.forEach((e) => {
+ ;(d[e].swiperLoopMoveDOM = !0),
+ u.prepend(d[e]),
+ (d[e].swiperLoopMoveDOM = !1)
+ }),
+ I &&
+ M.forEach((e) => {
+ ;(d[e].swiperLoopMoveDOM = !0),
+ u.append(d[e]),
+ (d[e].swiperLoopMoveDOM = !1)
+ }),
+ o.recalcSlides(),
+ 'auto' === m.slidesPerView
+ ? o.updateSlides()
+ : S &&
+ ((T.length > 0 && z) || (M.length > 0 && I)) &&
+ o.slides.forEach((e, t) => {
+ o.grid.updateSlide(t, e, o.slides)
+ }),
+ m.watchSlidesProgress && o.updateSlidesOffset(),
+ t)
+ )
+ if (T.length > 0 && z) {
+ if (void 0 === e) {
+ const e = o.slidesGrid[L],
+ t = o.slidesGrid[L + A] - e
+ l
+ ? o.setTranslate(o.translate - t)
+ : (o.slideTo(L + Math.ceil(A), 0, !1, !0),
+ a &&
+ ((o.touchEventsData.startTranslate =
+ o.touchEventsData.startTranslate - t),
+ (o.touchEventsData.currentTranslate =
+ o.touchEventsData.currentTranslate - t)))
+ } else if (a) {
+ const e = S ? T.length / m.grid.rows : T.length
+ o.slideTo(o.activeIndex + e, 0, !1, !0),
+ (o.touchEventsData.currentTranslate = o.translate)
+ }
+ } else if (M.length > 0 && I)
+ if (void 0 === e) {
+ const e = o.slidesGrid[L],
+ t = o.slidesGrid[L - $] - e
+ l
+ ? o.setTranslate(o.translate - t)
+ : (o.slideTo(L - $, 0, !1, !0),
+ a &&
+ ((o.touchEventsData.startTranslate =
+ o.touchEventsData.startTranslate - t),
+ (o.touchEventsData.currentTranslate =
+ o.touchEventsData.currentTranslate - t)))
+ } else {
+ const e = S ? M.length / m.grid.rows : M.length
+ o.slideTo(o.activeIndex - e, 0, !1, !0)
+ }
+ if (
+ ((o.allowSlidePrev = c),
+ (o.allowSlideNext = p),
+ o.controller && o.controller.control && !n)
+ ) {
+ const r = {
+ slideRealIndex: e,
+ direction: s,
+ setTranslate: a,
+ activeSlideIndex: i,
+ byController: !0,
+ }
+ Array.isArray(o.controller.control)
+ ? o.controller.control.forEach((e) => {
+ !e.destroyed &&
+ e.params.loop &&
+ e.loopFix({
+ ...r,
+ slideTo: e.params.slidesPerView === m.slidesPerView && t,
+ })
+ })
+ : o.controller.control instanceof o.constructor &&
+ o.controller.control.params.loop &&
+ o.controller.control.loopFix({
+ ...r,
+ slideTo:
+ o.controller.control.params.slidesPerView === m.slidesPerView &&
+ t,
+ })
+ }
+ o.emit('loopFix')
+ },
+ loopDestroy: function () {
+ const e = this,
+ { params: t, slidesEl: s } = e
+ if (!t.loop || !s || (e.virtual && e.params.virtual.enabled)) return
+ e.recalcSlides()
+ const a = []
+ e.slides.forEach((e) => {
+ const t =
+ void 0 === e.swiperSlideIndex
+ ? 1 * e.getAttribute('data-swiper-slide-index')
+ : e.swiperSlideIndex
+ a[t] = e
+ }),
+ e.slides.forEach((e) => {
+ e.removeAttribute('data-swiper-slide-index')
+ }),
+ a.forEach((e) => {
+ s.append(e)
+ }),
+ e.recalcSlides(),
+ e.slideTo(e.realIndex, 0)
+ },
+ }
+ function _(e, t, s) {
+ const a = r(),
+ { params: i } = e,
+ n = i.edgeSwipeDetection,
+ l = i.edgeSwipeThreshold
+ return (
+ !n ||
+ !(s <= l || s >= a.innerWidth - l) ||
+ ('prevent' === n && (t.preventDefault(), !0))
+ )
+ }
+ function F(e) {
+ const t = this,
+ s = a()
+ let i = e
+ i.originalEvent && (i = i.originalEvent)
+ const n = t.touchEventsData
+ if ('pointerdown' === i.type) {
+ if (null !== n.pointerId && n.pointerId !== i.pointerId) return
+ n.pointerId = i.pointerId
+ } else
+ 'touchstart' === i.type &&
+ 1 === i.targetTouches.length &&
+ (n.touchId = i.targetTouches[0].identifier)
+ if ('touchstart' === i.type) return void _(t, i, i.targetTouches[0].pageX)
+ const { params: l, touches: d, enabled: c } = t
+ if (!c) return
+ if (!l.simulateTouch && 'mouse' === i.pointerType) return
+ if (t.animating && l.preventInteractionOnTransition) return
+ !t.animating && l.cssMode && l.loop && t.loopFix()
+ let p = i.target
+ if (
+ 'wrapper' === l.touchEventsTarget &&
+ !(function (e, t) {
+ const s = r()
+ let a = t.contains(e)
+ !a &&
+ s.HTMLSlotElement &&
+ t instanceof HTMLSlotElement &&
+ ((a = [...t.assignedElements()].includes(e)),
+ a ||
+ (a = (function (e, t) {
+ const s = [t]
+ for (; s.length > 0; ) {
+ const t = s.shift()
+ if (e === t) return !0
+ s.push(
+ ...t.children,
+ ...(t.shadowRoot ? t.shadowRoot.children : []),
+ ...(t.assignedElements ? t.assignedElements() : [])
+ )
+ }
+ })(e, t)))
+ return a
+ })(p, t.wrapperEl)
+ )
+ return
+ if ('which' in i && 3 === i.which) return
+ if ('button' in i && i.button > 0) return
+ if (n.isTouched && n.isMoved) return
+ const u = !!l.noSwipingClass && '' !== l.noSwipingClass,
+ m = i.composedPath ? i.composedPath() : i.path
+ u && i.target && i.target.shadowRoot && m && (p = m[0])
+ const h = l.noSwipingSelector
+ ? l.noSwipingSelector
+ : `.${l.noSwipingClass}`,
+ f = !(!i.target || !i.target.shadowRoot)
+ if (
+ l.noSwiping &&
+ (f
+ ? (function (e, t = this) {
+ return (function t(s) {
+ if (!s || s === a() || s === r()) return null
+ s.assignedSlot && (s = s.assignedSlot)
+ const i = s.closest(e)
+ return i || s.getRootNode ? i || t(s.getRootNode().host) : null
+ })(t)
+ })(h, p)
+ : p.closest(h))
+ )
+ return void (t.allowClick = !0)
+ if (l.swipeHandler && !p.closest(l.swipeHandler)) return
+ ;(d.currentX = i.pageX), (d.currentY = i.pageY)
+ const g = d.currentX,
+ v = d.currentY
+ if (!_(t, i, g)) return
+ Object.assign(n, {
+ isTouched: !0,
+ isMoved: !1,
+ allowTouchCallbacks: !0,
+ isScrolling: void 0,
+ startMoving: void 0,
+ }),
+ (d.startX = g),
+ (d.startY = v),
+ (n.touchStartTime = o()),
+ (t.allowClick = !0),
+ t.updateSize(),
+ (t.swipeDirection = void 0),
+ l.threshold > 0 && (n.allowThresholdMove = !1)
+ let w = !0
+ p.matches(n.focusableElements) &&
+ ((w = !1), 'SELECT' === p.nodeName && (n.isTouched = !1)),
+ s.activeElement &&
+ s.activeElement.matches(n.focusableElements) &&
+ s.activeElement !== p &&
+ ('mouse' === i.pointerType ||
+ ('mouse' !== i.pointerType && !p.matches(n.focusableElements))) &&
+ s.activeElement.blur()
+ const b = w && t.allowTouchMove && l.touchStartPreventDefault
+ ;(!l.touchStartForcePreventDefault && !b) ||
+ p.isContentEditable ||
+ i.preventDefault(),
+ l.freeMode &&
+ l.freeMode.enabled &&
+ t.freeMode &&
+ t.animating &&
+ !l.cssMode &&
+ t.freeMode.onTouchStart(),
+ t.emit('touchStart', i)
+ }
+ function W(e) {
+ const t = a(),
+ s = this,
+ i = s.touchEventsData,
+ { params: r, touches: n, rtlTranslate: l, enabled: d } = s
+ if (!d) return
+ if (!r.simulateTouch && 'mouse' === e.pointerType) return
+ let c,
+ p = e
+ if ((p.originalEvent && (p = p.originalEvent), 'pointermove' === p.type)) {
+ if (null !== i.touchId) return
+ if (p.pointerId !== i.pointerId) return
+ }
+ if ('touchmove' === p.type) {
+ if (
+ ((c = [...p.changedTouches].find((e) => e.identifier === i.touchId)),
+ !c || c.identifier !== i.touchId)
+ )
+ return
+ } else c = p
+ if (!i.isTouched)
+ return void (
+ i.startMoving &&
+ i.isScrolling &&
+ s.emit('touchMoveOpposite', p)
+ )
+ const u = c.pageX,
+ m = c.pageY
+ if (p.preventedByNestedSwiper) return (n.startX = u), void (n.startY = m)
+ if (!s.allowTouchMove)
+ return (
+ p.target.matches(i.focusableElements) || (s.allowClick = !1),
+ void (
+ i.isTouched &&
+ (Object.assign(n, { startX: u, startY: m, currentX: u, currentY: m }),
+ (i.touchStartTime = o()))
+ )
+ )
+ if (r.touchReleaseOnEdges && !r.loop)
+ if (s.isVertical()) {
+ if (
+ (m < n.startY && s.translate <= s.maxTranslate()) ||
+ (m > n.startY && s.translate >= s.minTranslate())
+ )
+ return (i.isTouched = !1), void (i.isMoved = !1)
+ } else {
+ if (
+ l &&
+ ((u > n.startX && -s.translate <= s.maxTranslate()) ||
+ (u < n.startX && -s.translate >= s.minTranslate()))
+ )
+ return
+ if (
+ !l &&
+ ((u < n.startX && s.translate <= s.maxTranslate()) ||
+ (u > n.startX && s.translate >= s.minTranslate()))
+ )
+ return
+ }
+ if (
+ (t.activeElement &&
+ t.activeElement.matches(i.focusableElements) &&
+ t.activeElement !== p.target &&
+ 'mouse' !== p.pointerType &&
+ t.activeElement.blur(),
+ t.activeElement &&
+ p.target === t.activeElement &&
+ p.target.matches(i.focusableElements))
+ )
+ return (i.isMoved = !0), void (s.allowClick = !1)
+ i.allowTouchCallbacks && s.emit('touchMove', p),
+ (n.previousX = n.currentX),
+ (n.previousY = n.currentY),
+ (n.currentX = u),
+ (n.currentY = m)
+ const h = n.currentX - n.startX,
+ f = n.currentY - n.startY
+ if (s.params.threshold && Math.sqrt(h ** 2 + f ** 2) < s.params.threshold)
+ return
+ if (void 0 === i.isScrolling) {
+ let e
+ ;(s.isHorizontal() && n.currentY === n.startY) ||
+ (s.isVertical() && n.currentX === n.startX)
+ ? (i.isScrolling = !1)
+ : h * h + f * f >= 25 &&
+ ((e = (180 * Math.atan2(Math.abs(f), Math.abs(h))) / Math.PI),
+ (i.isScrolling = s.isHorizontal()
+ ? e > r.touchAngle
+ : 90 - e > r.touchAngle))
+ }
+ if (
+ (i.isScrolling && s.emit('touchMoveOpposite', p),
+ void 0 === i.startMoving &&
+ ((n.currentX === n.startX && n.currentY === n.startY) ||
+ (i.startMoving = !0)),
+ i.isScrolling ||
+ ('touchmove' === p.type && i.preventTouchMoveFromPointerMove))
+ )
+ return void (i.isTouched = !1)
+ if (!i.startMoving) return
+ ;(s.allowClick = !1),
+ !r.cssMode && p.cancelable && p.preventDefault(),
+ r.touchMoveStopPropagation && !r.nested && p.stopPropagation()
+ let g = s.isHorizontal() ? h : f,
+ v = s.isHorizontal() ? n.currentX - n.previousX : n.currentY - n.previousY
+ r.oneWayMovement &&
+ ((g = Math.abs(g) * (l ? 1 : -1)), (v = Math.abs(v) * (l ? 1 : -1))),
+ (n.diff = g),
+ (g *= r.touchRatio),
+ l && ((g = -g), (v = -v))
+ const w = s.touchesDirection
+ ;(s.swipeDirection = g > 0 ? 'prev' : 'next'),
+ (s.touchesDirection = v > 0 ? 'prev' : 'next')
+ const b = s.params.loop && !r.cssMode,
+ y =
+ ('next' === s.touchesDirection && s.allowSlideNext) ||
+ ('prev' === s.touchesDirection && s.allowSlidePrev)
+ if (!i.isMoved) {
+ if (
+ (b && y && s.loopFix({ direction: s.swipeDirection }),
+ (i.startTranslate = s.getTranslate()),
+ s.setTransition(0),
+ s.animating)
+ ) {
+ const e = new window.CustomEvent('transitionend', {
+ bubbles: !0,
+ cancelable: !0,
+ detail: { bySwiperTouchMove: !0 },
+ })
+ s.wrapperEl.dispatchEvent(e)
+ }
+ ;(i.allowMomentumBounce = !1),
+ !r.grabCursor ||
+ (!0 !== s.allowSlideNext && !0 !== s.allowSlidePrev) ||
+ s.setGrabCursor(!0),
+ s.emit('sliderFirstMove', p)
+ }
+ if (
+ (new Date().getTime(),
+ !1 !== r._loopSwapReset &&
+ i.isMoved &&
+ i.allowThresholdMove &&
+ w !== s.touchesDirection &&
+ b &&
+ y &&
+ Math.abs(g) >= 1)
+ )
+ return (
+ Object.assign(n, {
+ startX: u,
+ startY: m,
+ currentX: u,
+ currentY: m,
+ startTranslate: i.currentTranslate,
+ }),
+ (i.loopSwapReset = !0),
+ void (i.startTranslate = i.currentTranslate)
+ )
+ s.emit('sliderMove', p),
+ (i.isMoved = !0),
+ (i.currentTranslate = g + i.startTranslate)
+ let E = !0,
+ x = r.resistanceRatio
+ if (
+ (r.touchReleaseOnEdges && (x = 0),
+ g > 0
+ ? (b &&
+ y &&
+ i.allowThresholdMove &&
+ i.currentTranslate >
+ (r.centeredSlides
+ ? s.minTranslate() -
+ s.slidesSizesGrid[s.activeIndex + 1] -
+ ('auto' !== r.slidesPerView &&
+ s.slides.length - r.slidesPerView >= 2
+ ? s.slidesSizesGrid[s.activeIndex + 1] +
+ s.params.spaceBetween
+ : 0) -
+ s.params.spaceBetween
+ : s.minTranslate()) &&
+ s.loopFix({
+ direction: 'prev',
+ setTranslate: !0,
+ activeSlideIndex: 0,
+ }),
+ i.currentTranslate > s.minTranslate() &&
+ ((E = !1),
+ r.resistance &&
+ (i.currentTranslate =
+ s.minTranslate() -
+ 1 +
+ (-s.minTranslate() + i.startTranslate + g) ** x)))
+ : g < 0 &&
+ (b &&
+ y &&
+ i.allowThresholdMove &&
+ i.currentTranslate <
+ (r.centeredSlides
+ ? s.maxTranslate() +
+ s.slidesSizesGrid[s.slidesSizesGrid.length - 1] +
+ s.params.spaceBetween +
+ ('auto' !== r.slidesPerView &&
+ s.slides.length - r.slidesPerView >= 2
+ ? s.slidesSizesGrid[s.slidesSizesGrid.length - 1] +
+ s.params.spaceBetween
+ : 0)
+ : s.maxTranslate()) &&
+ s.loopFix({
+ direction: 'next',
+ setTranslate: !0,
+ activeSlideIndex:
+ s.slides.length -
+ ('auto' === r.slidesPerView
+ ? s.slidesPerViewDynamic()
+ : Math.ceil(parseFloat(r.slidesPerView, 10))),
+ }),
+ i.currentTranslate < s.maxTranslate() &&
+ ((E = !1),
+ r.resistance &&
+ (i.currentTranslate =
+ s.maxTranslate() +
+ 1 -
+ (s.maxTranslate() - i.startTranslate - g) ** x))),
+ E && (p.preventedByNestedSwiper = !0),
+ !s.allowSlideNext &&
+ 'next' === s.swipeDirection &&
+ i.currentTranslate < i.startTranslate &&
+ (i.currentTranslate = i.startTranslate),
+ !s.allowSlidePrev &&
+ 'prev' === s.swipeDirection &&
+ i.currentTranslate > i.startTranslate &&
+ (i.currentTranslate = i.startTranslate),
+ s.allowSlidePrev ||
+ s.allowSlideNext ||
+ (i.currentTranslate = i.startTranslate),
+ r.threshold > 0)
+ ) {
+ if (!(Math.abs(g) > r.threshold || i.allowThresholdMove))
+ return void (i.currentTranslate = i.startTranslate)
+ if (!i.allowThresholdMove)
+ return (
+ (i.allowThresholdMove = !0),
+ (n.startX = n.currentX),
+ (n.startY = n.currentY),
+ (i.currentTranslate = i.startTranslate),
+ void (n.diff = s.isHorizontal()
+ ? n.currentX - n.startX
+ : n.currentY - n.startY)
+ )
+ }
+ r.followFinger &&
+ !r.cssMode &&
+ (((r.freeMode && r.freeMode.enabled && s.freeMode) ||
+ r.watchSlidesProgress) &&
+ (s.updateActiveIndex(), s.updateSlidesClasses()),
+ r.freeMode &&
+ r.freeMode.enabled &&
+ s.freeMode &&
+ s.freeMode.onTouchMove(),
+ s.updateProgress(i.currentTranslate),
+ s.setTranslate(i.currentTranslate))
+ }
+ function j(e) {
+ const t = this,
+ s = t.touchEventsData
+ let a,
+ i = e
+ i.originalEvent && (i = i.originalEvent)
+ if ('touchend' === i.type || 'touchcancel' === i.type) {
+ if (
+ ((a = [...i.changedTouches].find((e) => e.identifier === s.touchId)),
+ !a || a.identifier !== s.touchId)
+ )
+ return
+ } else {
+ if (null !== s.touchId) return
+ if (i.pointerId !== s.pointerId) return
+ a = i
+ }
+ if (
+ ['pointercancel', 'pointerout', 'pointerleave', 'contextmenu'].includes(
+ i.type
+ )
+ ) {
+ if (
+ !(
+ ['pointercancel', 'contextmenu'].includes(i.type) &&
+ (t.browser.isSafari || t.browser.isWebView)
+ )
+ )
+ return
+ }
+ ;(s.pointerId = null), (s.touchId = null)
+ const {
+ params: r,
+ touches: n,
+ rtlTranslate: d,
+ slidesGrid: c,
+ enabled: p,
+ } = t
+ if (!p) return
+ if (!r.simulateTouch && 'mouse' === i.pointerType) return
+ if (
+ (s.allowTouchCallbacks && t.emit('touchEnd', i),
+ (s.allowTouchCallbacks = !1),
+ !s.isTouched)
+ )
+ return (
+ s.isMoved && r.grabCursor && t.setGrabCursor(!1),
+ (s.isMoved = !1),
+ void (s.startMoving = !1)
+ )
+ r.grabCursor &&
+ s.isMoved &&
+ s.isTouched &&
+ (!0 === t.allowSlideNext || !0 === t.allowSlidePrev) &&
+ t.setGrabCursor(!1)
+ const u = o(),
+ m = u - s.touchStartTime
+ if (t.allowClick) {
+ const e = i.path || (i.composedPath && i.composedPath())
+ t.updateClickedSlide((e && e[0]) || i.target, e),
+ t.emit('tap click', i),
+ m < 300 &&
+ u - s.lastClickTime < 300 &&
+ t.emit('doubleTap doubleClick', i)
+ }
+ if (
+ ((s.lastClickTime = o()),
+ l(() => {
+ t.destroyed || (t.allowClick = !0)
+ }),
+ !s.isTouched ||
+ !s.isMoved ||
+ !t.swipeDirection ||
+ (0 === n.diff && !s.loopSwapReset) ||
+ (s.currentTranslate === s.startTranslate && !s.loopSwapReset))
+ )
+ return (s.isTouched = !1), (s.isMoved = !1), void (s.startMoving = !1)
+ let h
+ if (
+ ((s.isTouched = !1),
+ (s.isMoved = !1),
+ (s.startMoving = !1),
+ (h = r.followFinger
+ ? d
+ ? t.translate
+ : -t.translate
+ : -s.currentTranslate),
+ r.cssMode)
+ )
+ return
+ if (r.freeMode && r.freeMode.enabled)
+ return void t.freeMode.onTouchEnd({ currentPos: h })
+ const f = h >= -t.maxTranslate() && !t.params.loop
+ let g = 0,
+ v = t.slidesSizesGrid[0]
+ for (
+ let e = 0;
+ e < c.length;
+ e += e < r.slidesPerGroupSkip ? 1 : r.slidesPerGroup
+ ) {
+ const t = e < r.slidesPerGroupSkip - 1 ? 1 : r.slidesPerGroup
+ void 0 !== c[e + t]
+ ? (f || (h >= c[e] && h < c[e + t])) && ((g = e), (v = c[e + t] - c[e]))
+ : (f || h >= c[e]) && ((g = e), (v = c[c.length - 1] - c[c.length - 2]))
+ }
+ let w = null,
+ b = null
+ r.rewind &&
+ (t.isBeginning
+ ? (b =
+ r.virtual && r.virtual.enabled && t.virtual
+ ? t.virtual.slides.length - 1
+ : t.slides.length - 1)
+ : t.isEnd && (w = 0))
+ const y = (h - c[g]) / v,
+ E = g < r.slidesPerGroupSkip - 1 ? 1 : r.slidesPerGroup
+ if (m > r.longSwipesMs) {
+ if (!r.longSwipes) return void t.slideTo(t.activeIndex)
+ 'next' === t.swipeDirection &&
+ (y >= r.longSwipesRatio
+ ? t.slideTo(r.rewind && t.isEnd ? w : g + E)
+ : t.slideTo(g)),
+ 'prev' === t.swipeDirection &&
+ (y > 1 - r.longSwipesRatio
+ ? t.slideTo(g + E)
+ : null !== b && y < 0 && Math.abs(y) > r.longSwipesRatio
+ ? t.slideTo(b)
+ : t.slideTo(g))
+ } else {
+ if (!r.shortSwipes) return void t.slideTo(t.activeIndex)
+ t.navigation &&
+ (i.target === t.navigation.nextEl || i.target === t.navigation.prevEl)
+ ? i.target === t.navigation.nextEl
+ ? t.slideTo(g + E)
+ : t.slideTo(g)
+ : ('next' === t.swipeDirection && t.slideTo(null !== w ? w : g + E),
+ 'prev' === t.swipeDirection && t.slideTo(null !== b ? b : g))
+ }
+ }
+ function U() {
+ const e = this,
+ { params: t, el: s } = e
+ if (s && 0 === s.offsetWidth) return
+ t.breakpoints && e.setBreakpoint()
+ const { allowSlideNext: a, allowSlidePrev: i, snapGrid: r } = e,
+ n = e.virtual && e.params.virtual.enabled
+ ;(e.allowSlideNext = !0),
+ (e.allowSlidePrev = !0),
+ e.updateSize(),
+ e.updateSlides(),
+ e.updateSlidesClasses()
+ const l = n && t.loop
+ !('auto' === t.slidesPerView || t.slidesPerView > 1) ||
+ !e.isEnd ||
+ e.isBeginning ||
+ e.params.centeredSlides ||
+ l
+ ? e.params.loop && !n
+ ? e.slideToLoop(e.realIndex, 0, !1, !0)
+ : e.slideTo(e.activeIndex, 0, !1, !0)
+ : e.slideTo(e.slides.length - 1, 0, !1, !0),
+ e.autoplay &&
+ e.autoplay.running &&
+ e.autoplay.paused &&
+ (clearTimeout(e.autoplay.resizeTimeout),
+ (e.autoplay.resizeTimeout = setTimeout(() => {
+ e.autoplay &&
+ e.autoplay.running &&
+ e.autoplay.paused &&
+ e.autoplay.resume()
+ }, 500))),
+ (e.allowSlidePrev = i),
+ (e.allowSlideNext = a),
+ e.params.watchOverflow && r !== e.snapGrid && e.checkOverflow()
+ }
+ function K(e) {
+ const t = this
+ t.enabled &&
+ (t.allowClick ||
+ (t.params.preventClicks && e.preventDefault(),
+ t.params.preventClicksPropagation &&
+ t.animating &&
+ (e.stopPropagation(), e.stopImmediatePropagation())))
+ }
+ function Z() {
+ const e = this,
+ { wrapperEl: t, rtlTranslate: s, enabled: a } = e
+ if (!a) return
+ let i
+ ;(e.previousTranslate = e.translate),
+ e.isHorizontal()
+ ? (e.translate = -t.scrollLeft)
+ : (e.translate = -t.scrollTop),
+ 0 === e.translate && (e.translate = 0),
+ e.updateActiveIndex(),
+ e.updateSlidesClasses()
+ const r = e.maxTranslate() - e.minTranslate()
+ ;(i = 0 === r ? 0 : (e.translate - e.minTranslate()) / r),
+ i !== e.progress && e.updateProgress(s ? -e.translate : e.translate),
+ e.emit('setTranslate', e.translate, !1)
+ }
+ function Q(e) {
+ const t = this
+ X(t, e.target),
+ t.params.cssMode ||
+ ('auto' !== t.params.slidesPerView && !t.params.autoHeight) ||
+ t.update()
+ }
+ function J() {
+ const e = this
+ e.documentTouchHandlerProceeded ||
+ ((e.documentTouchHandlerProceeded = !0),
+ e.params.touchReleaseOnEdges && (e.el.style.touchAction = 'auto'))
+ }
+ const ee = (e, t) => {
+ const s = a(),
+ { params: i, el: r, wrapperEl: n, device: l } = e,
+ o = !!i.nested,
+ d = 'on' === t ? 'addEventListener' : 'removeEventListener',
+ c = t
+ r &&
+ 'string' != typeof r &&
+ (s[d]('touchstart', e.onDocumentTouchStart, { passive: !1, capture: o }),
+ r[d]('touchstart', e.onTouchStart, { passive: !1 }),
+ r[d]('pointerdown', e.onTouchStart, { passive: !1 }),
+ s[d]('touchmove', e.onTouchMove, { passive: !1, capture: o }),
+ s[d]('pointermove', e.onTouchMove, { passive: !1, capture: o }),
+ s[d]('touchend', e.onTouchEnd, { passive: !0 }),
+ s[d]('pointerup', e.onTouchEnd, { passive: !0 }),
+ s[d]('pointercancel', e.onTouchEnd, { passive: !0 }),
+ s[d]('touchcancel', e.onTouchEnd, { passive: !0 }),
+ s[d]('pointerout', e.onTouchEnd, { passive: !0 }),
+ s[d]('pointerleave', e.onTouchEnd, { passive: !0 }),
+ s[d]('contextmenu', e.onTouchEnd, { passive: !0 }),
+ (i.preventClicks || i.preventClicksPropagation) &&
+ r[d]('click', e.onClick, !0),
+ i.cssMode && n[d]('scroll', e.onScroll),
+ i.updateOnWindowResize
+ ? e[c](
+ l.ios || l.android
+ ? 'resize orientationchange observerUpdate'
+ : 'resize observerUpdate',
+ U,
+ !0
+ )
+ : e[c]('observerUpdate', U, !0),
+ r[d]('load', e.onLoad, { capture: !0 }))
+ }
+ const te = (e, t) => e.grid && t.grid && t.grid.rows > 1
+ var se = {
+ init: !0,
+ direction: 'horizontal',
+ oneWayMovement: !1,
+ swiperElementNodeName: 'SWIPER-CONTAINER',
+ touchEventsTarget: 'wrapper',
+ initialSlide: 0,
+ speed: 300,
+ cssMode: !1,
+ updateOnWindowResize: !0,
+ resizeObserver: !0,
+ nested: !1,
+ createElements: !1,
+ eventsPrefix: 'swiper',
+ enabled: !0,
+ focusableElements: 'input, select, option, textarea, button, video, label',
+ width: null,
+ height: null,
+ preventInteractionOnTransition: !1,
+ userAgent: null,
+ url: null,
+ edgeSwipeDetection: !1,
+ edgeSwipeThreshold: 20,
+ autoHeight: !1,
+ setWrapperSize: !1,
+ virtualTranslate: !1,
+ effect: 'slide',
+ breakpoints: void 0,
+ breakpointsBase: 'window',
+ spaceBetween: 0,
+ slidesPerView: 1,
+ slidesPerGroup: 1,
+ slidesPerGroupSkip: 0,
+ slidesPerGroupAuto: !1,
+ centeredSlides: !1,
+ centeredSlidesBounds: !1,
+ slidesOffsetBefore: 0,
+ slidesOffsetAfter: 0,
+ normalizeSlideIndex: !0,
+ centerInsufficientSlides: !1,
+ watchOverflow: !0,
+ roundLengths: !1,
+ touchRatio: 1,
+ touchAngle: 45,
+ simulateTouch: !0,
+ shortSwipes: !0,
+ longSwipes: !0,
+ longSwipesRatio: 0.5,
+ longSwipesMs: 300,
+ followFinger: !0,
+ allowTouchMove: !0,
+ threshold: 5,
+ touchMoveStopPropagation: !1,
+ touchStartPreventDefault: !0,
+ touchStartForcePreventDefault: !1,
+ touchReleaseOnEdges: !1,
+ uniqueNavElements: !0,
+ resistance: !0,
+ resistanceRatio: 0.85,
+ watchSlidesProgress: !1,
+ grabCursor: !1,
+ preventClicks: !0,
+ preventClicksPropagation: !0,
+ slideToClickedSlide: !1,
+ loop: !1,
+ loopAddBlankSlides: !0,
+ loopAdditionalSlides: 0,
+ loopPreventsSliding: !0,
+ rewind: !1,
+ allowSlidePrev: !0,
+ allowSlideNext: !0,
+ swipeHandler: null,
+ noSwiping: !0,
+ noSwipingClass: 'swiper-no-swiping',
+ noSwipingSelector: null,
+ passiveListeners: !0,
+ maxBackfaceHiddenSlides: 10,
+ containerModifierClass: 'swiper-',
+ slideClass: 'swiper-slide',
+ slideBlankClass: 'swiper-slide-blank',
+ slideActiveClass: 'swiper-slide-active',
+ slideVisibleClass: 'swiper-slide-visible',
+ slideFullyVisibleClass: 'swiper-slide-fully-visible',
+ slideNextClass: 'swiper-slide-next',
+ slidePrevClass: 'swiper-slide-prev',
+ wrapperClass: 'swiper-wrapper',
+ lazyPreloaderClass: 'swiper-lazy-preloader',
+ lazyPreloadPrevNext: 0,
+ runCallbacksOnInit: !0,
+ _emitClasses: !1,
+ }
+ function ae(e, t) {
+ return function (s = {}) {
+ const a = Object.keys(s)[0],
+ i = s[a]
+ 'object' == typeof i && null !== i
+ ? (!0 === e[a] && (e[a] = { enabled: !0 }),
+ 'navigation' === a &&
+ e[a] &&
+ e[a].enabled &&
+ !e[a].prevEl &&
+ !e[a].nextEl &&
+ (e[a].auto = !0),
+ ['pagination', 'scrollbar'].indexOf(a) >= 0 &&
+ e[a] &&
+ e[a].enabled &&
+ !e[a].el &&
+ (e[a].auto = !0),
+ a in e && 'enabled' in i
+ ? ('object' != typeof e[a] ||
+ 'enabled' in e[a] ||
+ (e[a].enabled = !0),
+ e[a] || (e[a] = { enabled: !1 }),
+ u(t, s))
+ : u(t, s))
+ : u(t, s)
+ }
+ }
+ const ie = {
+ eventsEmitter: O,
+ update: H,
+ translate: N,
+ transition: {
+ setTransition: function (e, t) {
+ const s = this
+ s.params.cssMode ||
+ ((s.wrapperEl.style.transitionDuration = `${e}ms`),
+ (s.wrapperEl.style.transitionDelay = 0 === e ? '0ms' : '')),
+ s.emit('setTransition', e, t)
+ },
+ transitionStart: function (e = !0, t) {
+ const s = this,
+ { params: a } = s
+ a.cssMode ||
+ (a.autoHeight && s.updateAutoHeight(),
+ R({ swiper: s, runCallbacks: e, direction: t, step: 'Start' }))
+ },
+ transitionEnd: function (e = !0, t) {
+ const s = this,
+ { params: a } = s
+ ;(s.animating = !1),
+ a.cssMode ||
+ (s.setTransition(0),
+ R({ swiper: s, runCallbacks: e, direction: t, step: 'End' }))
+ },
+ },
+ slide: V,
+ loop: q,
+ grabCursor: {
+ setGrabCursor: function (e) {
+ const t = this
+ if (
+ !t.params.simulateTouch ||
+ (t.params.watchOverflow && t.isLocked) ||
+ t.params.cssMode
+ )
+ return
+ const s =
+ 'container' === t.params.touchEventsTarget ? t.el : t.wrapperEl
+ t.isElement && (t.__preventObserver__ = !0),
+ (s.style.cursor = 'move'),
+ (s.style.cursor = e ? 'grabbing' : 'grab'),
+ t.isElement &&
+ requestAnimationFrame(() => {
+ t.__preventObserver__ = !1
+ })
+ },
+ unsetGrabCursor: function () {
+ const e = this
+ ;(e.params.watchOverflow && e.isLocked) ||
+ e.params.cssMode ||
+ (e.isElement && (e.__preventObserver__ = !0),
+ (e[
+ 'container' === e.params.touchEventsTarget ? 'el' : 'wrapperEl'
+ ].style.cursor = ''),
+ e.isElement &&
+ requestAnimationFrame(() => {
+ e.__preventObserver__ = !1
+ }))
+ },
+ },
+ events: {
+ attachEvents: function () {
+ const e = this,
+ { params: t } = e
+ ;(e.onTouchStart = F.bind(e)),
+ (e.onTouchMove = W.bind(e)),
+ (e.onTouchEnd = j.bind(e)),
+ (e.onDocumentTouchStart = J.bind(e)),
+ t.cssMode && (e.onScroll = Z.bind(e)),
+ (e.onClick = K.bind(e)),
+ (e.onLoad = Q.bind(e)),
+ ee(e, 'on')
+ },
+ detachEvents: function () {
+ ee(this, 'off')
+ },
+ },
+ breakpoints: {
+ setBreakpoint: function () {
+ const e = this,
+ { realIndex: t, initialized: s, params: i, el: r } = e,
+ n = i.breakpoints
+ if (!n || (n && 0 === Object.keys(n).length)) return
+ const l = a(),
+ o =
+ 'window' !== i.breakpointsBase && i.breakpointsBase
+ ? 'container'
+ : i.breakpointsBase,
+ d =
+ ['window', 'container'].includes(i.breakpointsBase) ||
+ !i.breakpointsBase
+ ? e.el
+ : l.querySelector(i.breakpointsBase),
+ c = e.getBreakpoint(n, o, d)
+ if (!c || e.currentBreakpoint === c) return
+ const p = (c in n ? n[c] : void 0) || e.originalParams,
+ m = te(e, i),
+ h = te(e, p),
+ f = e.params.grabCursor,
+ g = p.grabCursor,
+ v = i.enabled
+ m && !h
+ ? (r.classList.remove(
+ `${i.containerModifierClass}grid`,
+ `${i.containerModifierClass}grid-column`
+ ),
+ e.emitContainerClasses())
+ : !m &&
+ h &&
+ (r.classList.add(`${i.containerModifierClass}grid`),
+ ((p.grid.fill && 'column' === p.grid.fill) ||
+ (!p.grid.fill && 'column' === i.grid.fill)) &&
+ r.classList.add(`${i.containerModifierClass}grid-column`),
+ e.emitContainerClasses()),
+ f && !g ? e.unsetGrabCursor() : !f && g && e.setGrabCursor(),
+ ['navigation', 'pagination', 'scrollbar'].forEach((t) => {
+ if (void 0 === p[t]) return
+ const s = i[t] && i[t].enabled,
+ a = p[t] && p[t].enabled
+ s && !a && e[t].disable(), !s && a && e[t].enable()
+ })
+ const w = p.direction && p.direction !== i.direction,
+ b = i.loop && (p.slidesPerView !== i.slidesPerView || w),
+ y = i.loop
+ w && s && e.changeDirection(), u(e.params, p)
+ const E = e.params.enabled,
+ x = e.params.loop
+ Object.assign(e, {
+ allowTouchMove: e.params.allowTouchMove,
+ allowSlideNext: e.params.allowSlideNext,
+ allowSlidePrev: e.params.allowSlidePrev,
+ }),
+ v && !E ? e.disable() : !v && E && e.enable(),
+ (e.currentBreakpoint = c),
+ e.emit('_beforeBreakpoint', p),
+ s &&
+ (b
+ ? (e.loopDestroy(), e.loopCreate(t), e.updateSlides())
+ : !y && x
+ ? (e.loopCreate(t), e.updateSlides())
+ : y && !x && e.loopDestroy()),
+ e.emit('breakpoint', p)
+ },
+ getBreakpoint: function (e, t = 'window', s) {
+ if (!e || ('container' === t && !s)) return
+ let a = !1
+ const i = r(),
+ n = 'window' === t ? i.innerHeight : s.clientHeight,
+ l = Object.keys(e).map((e) => {
+ if ('string' == typeof e && 0 === e.indexOf('@')) {
+ const t = parseFloat(e.substr(1))
+ return { value: n * t, point: e }
+ }
+ return { value: e, point: e }
+ })
+ l.sort((e, t) => parseInt(e.value, 10) - parseInt(t.value, 10))
+ for (let e = 0; e < l.length; e += 1) {
+ const { point: r, value: n } = l[e]
+ 'window' === t
+ ? i.matchMedia(`(min-width: ${n}px)`).matches && (a = r)
+ : n <= s.clientWidth && (a = r)
+ }
+ return a || 'max'
+ },
+ },
+ checkOverflow: {
+ checkOverflow: function () {
+ const e = this,
+ { isLocked: t, params: s } = e,
+ { slidesOffsetBefore: a } = s
+ if (a) {
+ const t = e.slides.length - 1,
+ s = e.slidesGrid[t] + e.slidesSizesGrid[t] + 2 * a
+ e.isLocked = e.size > s
+ } else e.isLocked = 1 === e.snapGrid.length
+ !0 === s.allowSlideNext && (e.allowSlideNext = !e.isLocked),
+ !0 === s.allowSlidePrev && (e.allowSlidePrev = !e.isLocked),
+ t && t !== e.isLocked && (e.isEnd = !1),
+ t !== e.isLocked && e.emit(e.isLocked ? 'lock' : 'unlock')
+ },
+ },
+ classes: {
+ addClasses: function () {
+ const e = this,
+ { classNames: t, params: s, rtl: a, el: i, device: r } = e,
+ n = (function (e, t) {
+ const s = []
+ return (
+ e.forEach((e) => {
+ 'object' == typeof e
+ ? Object.keys(e).forEach((a) => {
+ e[a] && s.push(t + a)
+ })
+ : 'string' == typeof e && s.push(t + e)
+ }),
+ s
+ )
+ })(
+ [
+ 'initialized',
+ s.direction,
+ { 'free-mode': e.params.freeMode && s.freeMode.enabled },
+ { autoheight: s.autoHeight },
+ { rtl: a },
+ { grid: s.grid && s.grid.rows > 1 },
+ {
+ 'grid-column':
+ s.grid && s.grid.rows > 1 && 'column' === s.grid.fill,
+ },
+ { android: r.android },
+ { ios: r.ios },
+ { 'css-mode': s.cssMode },
+ { centered: s.cssMode && s.centeredSlides },
+ { 'watch-progress': s.watchSlidesProgress },
+ ],
+ s.containerModifierClass
+ )
+ t.push(...n), i.classList.add(...t), e.emitContainerClasses()
+ },
+ removeClasses: function () {
+ const { el: e, classNames: t } = this
+ e &&
+ 'string' != typeof e &&
+ (e.classList.remove(...t), this.emitContainerClasses())
+ },
+ },
+ },
+ re = {}
+ class ne {
+ constructor(...e) {
+ let t, s
+ 1 === e.length &&
+ e[0].constructor &&
+ 'Object' === Object.prototype.toString.call(e[0]).slice(8, -1)
+ ? (s = e[0])
+ : ([t, s] = e),
+ s || (s = {}),
+ (s = u({}, s)),
+ t && !s.el && (s.el = t)
+ const i = a()
+ if (
+ s.el &&
+ 'string' == typeof s.el &&
+ i.querySelectorAll(s.el).length > 1
+ ) {
+ const e = []
+ return (
+ i.querySelectorAll(s.el).forEach((t) => {
+ const a = u({}, s, { el: t })
+ e.push(new ne(a))
+ }),
+ e
+ )
+ }
+ const r = this
+ ;(r.__swiper__ = !0),
+ (r.support = A()),
+ (r.device = $({ userAgent: s.userAgent })),
+ (r.browser = k()),
+ (r.eventsListeners = {}),
+ (r.eventsAnyListeners = []),
+ (r.modules = [...r.__modules__]),
+ s.modules && Array.isArray(s.modules) && r.modules.push(...s.modules)
+ const n = {}
+ r.modules.forEach((e) => {
+ e({
+ params: s,
+ swiper: r,
+ extendParams: ae(s, n),
+ on: r.on.bind(r),
+ once: r.once.bind(r),
+ off: r.off.bind(r),
+ emit: r.emit.bind(r),
+ })
+ })
+ const l = u({}, se, n)
+ return (
+ (r.params = u({}, l, re, s)),
+ (r.originalParams = u({}, r.params)),
+ (r.passedParams = u({}, s)),
+ r.params &&
+ r.params.on &&
+ Object.keys(r.params.on).forEach((e) => {
+ r.on(e, r.params.on[e])
+ }),
+ r.params && r.params.onAny && r.onAny(r.params.onAny),
+ Object.assign(r, {
+ enabled: r.params.enabled,
+ el: t,
+ classNames: [],
+ slides: [],
+ slidesGrid: [],
+ snapGrid: [],
+ slidesSizesGrid: [],
+ isHorizontal: () => 'horizontal' === r.params.direction,
+ isVertical: () => 'vertical' === r.params.direction,
+ activeIndex: 0,
+ realIndex: 0,
+ isBeginning: !0,
+ isEnd: !1,
+ translate: 0,
+ previousTranslate: 0,
+ progress: 0,
+ velocity: 0,
+ animating: !1,
+ cssOverflowAdjustment() {
+ return Math.trunc(this.translate / 2 ** 23) * 2 ** 23
+ },
+ allowSlideNext: r.params.allowSlideNext,
+ allowSlidePrev: r.params.allowSlidePrev,
+ touchEventsData: {
+ isTouched: void 0,
+ isMoved: void 0,
+ allowTouchCallbacks: void 0,
+ touchStartTime: void 0,
+ isScrolling: void 0,
+ currentTranslate: void 0,
+ startTranslate: void 0,
+ allowThresholdMove: void 0,
+ focusableElements: r.params.focusableElements,
+ lastClickTime: 0,
+ clickTimeout: void 0,
+ velocities: [],
+ allowMomentumBounce: void 0,
+ startMoving: void 0,
+ pointerId: null,
+ touchId: null,
+ },
+ allowClick: !0,
+ allowTouchMove: r.params.allowTouchMove,
+ touches: { startX: 0, startY: 0, currentX: 0, currentY: 0, diff: 0 },
+ imagesToLoad: [],
+ imagesLoaded: 0,
+ }),
+ r.emit('_swiper'),
+ r.params.init && r.init(),
+ r
+ )
+ }
+ getDirectionLabel(e) {
+ return this.isHorizontal()
+ ? e
+ : {
+ width: 'height',
+ 'margin-top': 'margin-left',
+ 'margin-bottom ': 'margin-right',
+ 'margin-left': 'margin-top',
+ 'margin-right': 'margin-bottom',
+ 'padding-left': 'padding-top',
+ 'padding-right': 'padding-bottom',
+ marginRight: 'marginBottom',
+ }[e]
+ }
+ getSlideIndex(e) {
+ const { slidesEl: t, params: s } = this,
+ a = E(g(t, `.${s.slideClass}, swiper-slide`)[0])
+ return E(e) - a
+ }
+ getSlideIndexByData(e) {
+ return this.getSlideIndex(
+ this.slides.find(
+ (t) => 1 * t.getAttribute('data-swiper-slide-index') === e
+ )
+ )
+ }
+ getSlideIndexWhenGrid(e) {
+ return (
+ this.grid &&
+ this.params.grid &&
+ this.params.grid.rows > 1 &&
+ ('column' === this.params.grid.fill
+ ? (e = Math.floor(e / this.params.grid.rows))
+ : 'row' === this.params.grid.fill &&
+ (e %= Math.ceil(this.slides.length / this.params.grid.rows))),
+ e
+ )
+ }
+ recalcSlides() {
+ const { slidesEl: e, params: t } = this
+ this.slides = g(e, `.${t.slideClass}, swiper-slide`)
+ }
+ enable() {
+ const e = this
+ e.enabled ||
+ ((e.enabled = !0),
+ e.params.grabCursor && e.setGrabCursor(),
+ e.emit('enable'))
+ }
+ disable() {
+ const e = this
+ e.enabled &&
+ ((e.enabled = !1),
+ e.params.grabCursor && e.unsetGrabCursor(),
+ e.emit('disable'))
+ }
+ setProgress(e, t) {
+ const s = this
+ e = Math.min(Math.max(e, 0), 1)
+ const a = s.minTranslate(),
+ i = (s.maxTranslate() - a) * e + a
+ s.translateTo(i, void 0 === t ? 0 : t),
+ s.updateActiveIndex(),
+ s.updateSlidesClasses()
+ }
+ emitContainerClasses() {
+ const e = this
+ if (!e.params._emitClasses || !e.el) return
+ const t = e.el.className
+ .split(' ')
+ .filter(
+ (t) =>
+ 0 === t.indexOf('swiper') ||
+ 0 === t.indexOf(e.params.containerModifierClass)
+ )
+ e.emit('_containerClasses', t.join(' '))
+ }
+ getSlideClasses(e) {
+ const t = this
+ return t.destroyed
+ ? ''
+ : e.className
+ .split(' ')
+ .filter(
+ (e) =>
+ 0 === e.indexOf('swiper-slide') ||
+ 0 === e.indexOf(t.params.slideClass)
+ )
+ .join(' ')
+ }
+ emitSlidesClasses() {
+ const e = this
+ if (!e.params._emitClasses || !e.el) return
+ const t = []
+ e.slides.forEach((s) => {
+ const a = e.getSlideClasses(s)
+ t.push({ slideEl: s, classNames: a }), e.emit('_slideClass', s, a)
+ }),
+ e.emit('_slideClasses', t)
+ }
+ slidesPerViewDynamic(e = 'current', t = !1) {
+ const {
+ params: s,
+ slides: a,
+ slidesGrid: i,
+ slidesSizesGrid: r,
+ size: n,
+ activeIndex: l,
+ } = this
+ let o = 1
+ if ('number' == typeof s.slidesPerView) return s.slidesPerView
+ if (s.centeredSlides) {
+ let e,
+ t = a[l] ? Math.ceil(a[l].swiperSlideSize) : 0
+ for (let s = l + 1; s < a.length; s += 1)
+ a[s] &&
+ !e &&
+ ((t += Math.ceil(a[s].swiperSlideSize)),
+ (o += 1),
+ t > n && (e = !0))
+ for (let s = l - 1; s >= 0; s -= 1)
+ a[s] &&
+ !e &&
+ ((t += a[s].swiperSlideSize), (o += 1), t > n && (e = !0))
+ } else if ('current' === e)
+ for (let e = l + 1; e < a.length; e += 1) {
+ ;(t ? i[e] + r[e] - i[l] < n : i[e] - i[l] < n) && (o += 1)
+ }
+ else
+ for (let e = l - 1; e >= 0; e -= 1) {
+ i[l] - i[e] < n && (o += 1)
+ }
+ return o
+ }
+ update() {
+ const e = this
+ if (!e || e.destroyed) return
+ const { snapGrid: t, params: s } = e
+ function a() {
+ const t = e.rtlTranslate ? -1 * e.translate : e.translate,
+ s = Math.min(Math.max(t, e.maxTranslate()), e.minTranslate())
+ e.setTranslate(s), e.updateActiveIndex(), e.updateSlidesClasses()
+ }
+ let i
+ if (
+ (s.breakpoints && e.setBreakpoint(),
+ [...e.el.querySelectorAll('[loading="lazy"]')].forEach((t) => {
+ t.complete && X(e, t)
+ }),
+ e.updateSize(),
+ e.updateSlides(),
+ e.updateProgress(),
+ e.updateSlidesClasses(),
+ s.freeMode && s.freeMode.enabled && !s.cssMode)
+ )
+ a(), s.autoHeight && e.updateAutoHeight()
+ else {
+ if (
+ ('auto' === s.slidesPerView || s.slidesPerView > 1) &&
+ e.isEnd &&
+ !s.centeredSlides
+ ) {
+ const t = e.virtual && s.virtual.enabled ? e.virtual.slides : e.slides
+ i = e.slideTo(t.length - 1, 0, !1, !0)
+ } else i = e.slideTo(e.activeIndex, 0, !1, !0)
+ i || a()
+ }
+ s.watchOverflow && t !== e.snapGrid && e.checkOverflow(), e.emit('update')
+ }
+ changeDirection(e, t = !0) {
+ const s = this,
+ a = s.params.direction
+ return (
+ e || (e = 'horizontal' === a ? 'vertical' : 'horizontal'),
+ e === a ||
+ ('horizontal' !== e && 'vertical' !== e) ||
+ (s.el.classList.remove(`${s.params.containerModifierClass}${a}`),
+ s.el.classList.add(`${s.params.containerModifierClass}${e}`),
+ s.emitContainerClasses(),
+ (s.params.direction = e),
+ s.slides.forEach((t) => {
+ 'vertical' === e ? (t.style.width = '') : (t.style.height = '')
+ }),
+ s.emit('changeDirection'),
+ t && s.update()),
+ s
+ )
+ }
+ changeLanguageDirection(e) {
+ const t = this
+ ;(t.rtl && 'rtl' === e) ||
+ (!t.rtl && 'ltr' === e) ||
+ ((t.rtl = 'rtl' === e),
+ (t.rtlTranslate = 'horizontal' === t.params.direction && t.rtl),
+ t.rtl
+ ? (t.el.classList.add(`${t.params.containerModifierClass}rtl`),
+ (t.el.dir = 'rtl'))
+ : (t.el.classList.remove(`${t.params.containerModifierClass}rtl`),
+ (t.el.dir = 'ltr')),
+ t.update())
+ }
+ mount(e) {
+ const t = this
+ if (t.mounted) return !0
+ let s = e || t.params.el
+ if (('string' == typeof s && (s = document.querySelector(s)), !s))
+ return !1
+ ;(s.swiper = t),
+ s.parentNode &&
+ s.parentNode.host &&
+ s.parentNode.host.nodeName ===
+ t.params.swiperElementNodeName.toUpperCase() &&
+ (t.isElement = !0)
+ const a = () =>
+ `.${(t.params.wrapperClass || '').trim().split(' ').join('.')}`
+ let i = (() => {
+ if (s && s.shadowRoot && s.shadowRoot.querySelector) {
+ return s.shadowRoot.querySelector(a())
+ }
+ return g(s, a())[0]
+ })()
+ return (
+ !i &&
+ t.params.createElements &&
+ ((i = w('div', t.params.wrapperClass)),
+ s.append(i),
+ g(s, `.${t.params.slideClass}`).forEach((e) => {
+ i.append(e)
+ })),
+ Object.assign(t, {
+ el: s,
+ wrapperEl: i,
+ slidesEl:
+ t.isElement && !s.parentNode.host.slideSlots
+ ? s.parentNode.host
+ : i,
+ hostEl: t.isElement ? s.parentNode.host : s,
+ mounted: !0,
+ rtl: 'rtl' === s.dir.toLowerCase() || 'rtl' === y(s, 'direction'),
+ rtlTranslate:
+ 'horizontal' === t.params.direction &&
+ ('rtl' === s.dir.toLowerCase() || 'rtl' === y(s, 'direction')),
+ wrongRTL: '-webkit-box' === y(i, 'display'),
+ }),
+ !0
+ )
+ }
+ init(e) {
+ const t = this
+ if (t.initialized) return t
+ if (!1 === t.mount(e)) return t
+ t.emit('beforeInit'),
+ t.params.breakpoints && t.setBreakpoint(),
+ t.addClasses(),
+ t.updateSize(),
+ t.updateSlides(),
+ t.params.watchOverflow && t.checkOverflow(),
+ t.params.grabCursor && t.enabled && t.setGrabCursor(),
+ t.params.loop && t.virtual && t.params.virtual.enabled
+ ? t.slideTo(
+ t.params.initialSlide + t.virtual.slidesBefore,
+ 0,
+ t.params.runCallbacksOnInit,
+ !1,
+ !0
+ )
+ : t.slideTo(
+ t.params.initialSlide,
+ 0,
+ t.params.runCallbacksOnInit,
+ !1,
+ !0
+ ),
+ t.params.loop && t.loopCreate(void 0, !0),
+ t.attachEvents()
+ const s = [...t.el.querySelectorAll('[loading="lazy"]')]
+ return (
+ t.isElement && s.push(...t.hostEl.querySelectorAll('[loading="lazy"]')),
+ s.forEach((e) => {
+ e.complete
+ ? X(t, e)
+ : e.addEventListener('load', (e) => {
+ X(t, e.target)
+ })
+ }),
+ Y(t),
+ (t.initialized = !0),
+ Y(t),
+ t.emit('init'),
+ t.emit('afterInit'),
+ t
+ )
+ }
+ destroy(e = !0, t = !0) {
+ const s = this,
+ { params: a, el: i, wrapperEl: r, slides: n } = s
+ return (
+ void 0 === s.params ||
+ s.destroyed ||
+ (s.emit('beforeDestroy'),
+ (s.initialized = !1),
+ s.detachEvents(),
+ a.loop && s.loopDestroy(),
+ t &&
+ (s.removeClasses(),
+ i && 'string' != typeof i && i.removeAttribute('style'),
+ r && r.removeAttribute('style'),
+ n &&
+ n.length &&
+ n.forEach((e) => {
+ e.classList.remove(
+ a.slideVisibleClass,
+ a.slideFullyVisibleClass,
+ a.slideActiveClass,
+ a.slideNextClass,
+ a.slidePrevClass
+ ),
+ e.removeAttribute('style'),
+ e.removeAttribute('data-swiper-slide-index')
+ })),
+ s.emit('destroy'),
+ Object.keys(s.eventsListeners).forEach((e) => {
+ s.off(e)
+ }),
+ !1 !== e &&
+ (s.el && 'string' != typeof s.el && (s.el.swiper = null),
+ (function (e) {
+ const t = e
+ Object.keys(t).forEach((e) => {
+ try {
+ t[e] = null
+ } catch (e) {}
+ try {
+ delete t[e]
+ } catch (e) {}
+ })
+ })(s)),
+ (s.destroyed = !0)),
+ null
+ )
+ }
+ static extendDefaults(e) {
+ u(re, e)
+ }
+ static get extendedDefaults() {
+ return re
+ }
+ static get defaults() {
+ return se
+ }
+ static installModule(e) {
+ ne.prototype.__modules__ || (ne.prototype.__modules__ = [])
+ const t = ne.prototype.__modules__
+ 'function' == typeof e && t.indexOf(e) < 0 && t.push(e)
+ }
+ static use(e) {
+ return Array.isArray(e)
+ ? (e.forEach((e) => ne.installModule(e)), ne)
+ : (ne.installModule(e), ne)
+ }
+ }
+ function le(e, t, s, a) {
+ return (
+ e.params.createElements &&
+ Object.keys(a).forEach((i) => {
+ if (!s[i] && !0 === s.auto) {
+ let r = g(e.el, `.${a[i]}`)[0]
+ r || ((r = w('div', a[i])), (r.className = a[i]), e.el.append(r)),
+ (s[i] = r),
+ (t[i] = r)
+ }
+ }),
+ s
+ )
+ }
+ Object.keys(ie).forEach((e) => {
+ Object.keys(ie[e]).forEach((t) => {
+ ne.prototype[t] = ie[e][t]
+ })
+ }),
+ ne.use([
+ function ({ swiper: e, on: t, emit: s }) {
+ const a = r()
+ let i = null,
+ n = null
+ const l = () => {
+ e &&
+ !e.destroyed &&
+ e.initialized &&
+ (s('beforeResize'), s('resize'))
+ },
+ o = () => {
+ e && !e.destroyed && e.initialized && s('orientationchange')
+ }
+ t('init', () => {
+ e.params.resizeObserver && void 0 !== a.ResizeObserver
+ ? e &&
+ !e.destroyed &&
+ e.initialized &&
+ ((i = new ResizeObserver((t) => {
+ n = a.requestAnimationFrame(() => {
+ const { width: s, height: a } = e
+ let i = s,
+ r = a
+ t.forEach(
+ ({ contentBoxSize: t, contentRect: s, target: a }) => {
+ ;(a && a !== e.el) ||
+ ((i = s ? s.width : (t[0] || t).inlineSize),
+ (r = s ? s.height : (t[0] || t).blockSize))
+ }
+ ),
+ (i === s && r === a) || l()
+ })
+ })),
+ i.observe(e.el))
+ : (a.addEventListener('resize', l),
+ a.addEventListener('orientationchange', o))
+ }),
+ t('destroy', () => {
+ n && a.cancelAnimationFrame(n),
+ i && i.unobserve && e.el && (i.unobserve(e.el), (i = null)),
+ a.removeEventListener('resize', l),
+ a.removeEventListener('orientationchange', o)
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: a }) {
+ const i = [],
+ n = r(),
+ l = (t, s = {}) => {
+ const r = new (n.MutationObserver || n.WebkitMutationObserver)(
+ (t) => {
+ if (e.__preventObserver__) return
+ if (1 === t.length) return void a('observerUpdate', t[0])
+ const s = function () {
+ a('observerUpdate', t[0])
+ }
+ n.requestAnimationFrame
+ ? n.requestAnimationFrame(s)
+ : n.setTimeout(s, 0)
+ }
+ )
+ r.observe(t, {
+ attributes: void 0 === s.attributes || s.attributes,
+ childList: e.isElement || (void 0 === s.childList || s).childList,
+ characterData: void 0 === s.characterData || s.characterData,
+ }),
+ i.push(r)
+ }
+ t({ observer: !1, observeParents: !1, observeSlideChildren: !1 }),
+ s('init', () => {
+ if (e.params.observer) {
+ if (e.params.observeParents) {
+ const t = x(e.hostEl)
+ for (let e = 0; e < t.length; e += 1) l(t[e])
+ }
+ l(e.hostEl, { childList: e.params.observeSlideChildren }),
+ l(e.wrapperEl, { attributes: !1 })
+ }
+ }),
+ s('destroy', () => {
+ i.forEach((e) => {
+ e.disconnect()
+ }),
+ i.splice(0, i.length)
+ })
+ },
+ ])
+ const oe =
+ ''
+ function de(e = '') {
+ return `.${e
+ .trim()
+ .replace(/([\.:!+\/()[\]])/g, '\\$1')
+ .replace(/ /g, '.')}`
+ }
+ function ce(e) {
+ const t = this,
+ { params: s, slidesEl: a } = t
+ s.loop && t.loopDestroy()
+ const i = (e) => {
+ if ('string' == typeof e) {
+ const t = document.createElement('div')
+ P(t, e), a.append(t.children[0]), P(t, '')
+ } else a.append(e)
+ }
+ if ('object' == typeof e && 'length' in e)
+ for (let t = 0; t < e.length; t += 1) e[t] && i(e[t])
+ else i(e)
+ t.recalcSlides(),
+ s.loop && t.loopCreate(),
+ (s.observer && !t.isElement) || t.update()
+ }
+ function pe(e) {
+ const t = this,
+ { params: s, activeIndex: a, slidesEl: i } = t
+ s.loop && t.loopDestroy()
+ let r = a + 1
+ const n = (e) => {
+ if ('string' == typeof e) {
+ const t = document.createElement('div')
+ P(t, e), i.prepend(t.children[0]), P(t, '')
+ } else i.prepend(e)
+ }
+ if ('object' == typeof e && 'length' in e) {
+ for (let t = 0; t < e.length; t += 1) e[t] && n(e[t])
+ r = a + e.length
+ } else n(e)
+ t.recalcSlides(),
+ s.loop && t.loopCreate(),
+ (s.observer && !t.isElement) || t.update(),
+ t.slideTo(r, 0, !1)
+ }
+ function ue(e, t) {
+ const s = this,
+ { params: a, activeIndex: i, slidesEl: r } = s
+ let n = i
+ a.loop && ((n -= s.loopedSlides), s.loopDestroy(), s.recalcSlides())
+ const l = s.slides.length
+ if (e <= 0) return void s.prependSlide(t)
+ if (e >= l) return void s.appendSlide(t)
+ let o = n > e ? n + 1 : n
+ const d = []
+ for (let t = l - 1; t >= e; t -= 1) {
+ const e = s.slides[t]
+ e.remove(), d.unshift(e)
+ }
+ if ('object' == typeof t && 'length' in t) {
+ for (let e = 0; e < t.length; e += 1) t[e] && r.append(t[e])
+ o = n > e ? n + t.length : n
+ } else r.append(t)
+ for (let e = 0; e < d.length; e += 1) r.append(d[e])
+ s.recalcSlides(),
+ a.loop && s.loopCreate(),
+ (a.observer && !s.isElement) || s.update(),
+ a.loop ? s.slideTo(o + s.loopedSlides, 0, !1) : s.slideTo(o, 0, !1)
+ }
+ function me(e) {
+ const t = this,
+ { params: s, activeIndex: a } = t
+ let i = a
+ s.loop && ((i -= t.loopedSlides), t.loopDestroy())
+ let r,
+ n = i
+ if ('object' == typeof e && 'length' in e) {
+ for (let s = 0; s < e.length; s += 1)
+ (r = e[s]), t.slides[r] && t.slides[r].remove(), r < n && (n -= 1)
+ n = Math.max(n, 0)
+ } else
+ (r = e),
+ t.slides[r] && t.slides[r].remove(),
+ r < n && (n -= 1),
+ (n = Math.max(n, 0))
+ t.recalcSlides(),
+ s.loop && t.loopCreate(),
+ (s.observer && !t.isElement) || t.update(),
+ s.loop ? t.slideTo(n + t.loopedSlides, 0, !1) : t.slideTo(n, 0, !1)
+ }
+ function he() {
+ const e = this,
+ t = []
+ for (let s = 0; s < e.slides.length; s += 1) t.push(s)
+ e.removeSlide(t)
+ }
+ function fe(e) {
+ const {
+ effect: t,
+ swiper: s,
+ on: a,
+ setTranslate: i,
+ setTransition: r,
+ overwriteParams: n,
+ perspective: l,
+ recreateShadows: o,
+ getEffectParams: d,
+ } = e
+ let c
+ a('beforeInit', () => {
+ if (s.params.effect !== t) return
+ s.classNames.push(`${s.params.containerModifierClass}${t}`),
+ l && l() && s.classNames.push(`${s.params.containerModifierClass}3d`)
+ const e = n ? n() : {}
+ Object.assign(s.params, e), Object.assign(s.originalParams, e)
+ }),
+ a('setTranslate _virtualUpdated', () => {
+ s.params.effect === t && i()
+ }),
+ a('setTransition', (e, a) => {
+ s.params.effect === t && r(a)
+ }),
+ a('transitionEnd', () => {
+ if (s.params.effect === t && o) {
+ if (!d || !d().slideShadows) return
+ s.slides.forEach((e) => {
+ e.querySelectorAll(
+ '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
+ ).forEach((e) => e.remove())
+ }),
+ o()
+ }
+ }),
+ a('virtualUpdate', () => {
+ s.params.effect === t &&
+ (s.slides.length || (c = !0),
+ requestAnimationFrame(() => {
+ c && s.slides && s.slides.length && (i(), (c = !1))
+ }))
+ })
+ }
+ function ge(e, t) {
+ const s = f(t)
+ return (
+ s !== t &&
+ ((s.style.backfaceVisibility = 'hidden'),
+ (s.style['-webkit-backface-visibility'] = 'hidden')),
+ s
+ )
+ }
+ function ve({ swiper: e, duration: t, transformElements: s, allSlides: a }) {
+ const { activeIndex: i } = e
+ if (e.params.virtualTranslate && 0 !== t) {
+ let t,
+ r = !1
+ ;(t = a
+ ? s
+ : s.filter((t) => {
+ const s = t.classList.contains('swiper-slide-transform')
+ ? ((t) => {
+ if (!t.parentElement)
+ return e.slides.find(
+ (e) => e.shadowRoot && e.shadowRoot === t.parentNode
+ )
+ return t.parentElement
+ })(t)
+ : t
+ return e.getSlideIndex(s) === i
+ })),
+ t.forEach((t) => {
+ S(t, () => {
+ if (r) return
+ if (!e || e.destroyed) return
+ ;(r = !0), (e.animating = !1)
+ const t = new window.CustomEvent('transitionend', {
+ bubbles: !0,
+ cancelable: !0,
+ })
+ e.wrapperEl.dispatchEvent(t)
+ })
+ })
+ }
+ }
+ function we(e, t, s) {
+ const a = `swiper-slide-shadow${s ? `-${s}` : ''}${
+ e ? ` swiper-slide-shadow-${e}` : ''
+ }`,
+ i = f(t)
+ let r = i.querySelector(`.${a.split(' ').join('.')}`)
+ return r || ((r = w('div', a.split(' '))), i.append(r)), r
+ }
+ const be = [
+ function ({ swiper: e, extendParams: t, on: s, emit: i }) {
+ let r
+ t({
+ virtual: {
+ enabled: !1,
+ slides: [],
+ cache: !0,
+ slidesPerViewAutoSlideSize: 320,
+ renderSlide: null,
+ renderExternal: null,
+ renderExternalUpdate: !0,
+ addSlidesBefore: 0,
+ addSlidesAfter: 0,
+ },
+ })
+ const n = a()
+ e.virtual = {
+ cache: {},
+ from: void 0,
+ to: void 0,
+ slides: [],
+ offset: 0,
+ slidesGrid: [],
+ }
+ const l = n.createElement('div')
+ function o(t, s) {
+ const a = e.params.virtual
+ if (a.cache && e.virtual.cache[s]) return e.virtual.cache[s]
+ let i
+ return (
+ a.renderSlide
+ ? ((i = a.renderSlide.call(e, t, s)),
+ 'string' == typeof i && (P(l, i), (i = l.children[0])))
+ : (i = e.isElement
+ ? w('swiper-slide')
+ : w('div', e.params.slideClass)),
+ i.setAttribute('data-swiper-slide-index', s),
+ a.renderSlide || P(i, t),
+ a.cache && (e.virtual.cache[s] = i),
+ i
+ )
+ }
+ function d(t, s, a) {
+ const {
+ slidesPerGroup: r,
+ centeredSlides: n,
+ slidesPerView: l,
+ loop: d,
+ initialSlide: c,
+ } = e.params
+ if (s && !d && c > 0) return
+ const {
+ addSlidesBefore: p,
+ addSlidesAfter: u,
+ slidesPerViewAutoSlideSize: m,
+ } = e.params.virtual,
+ { from: h, to: f, slides: v, slidesGrid: w, offset: b } = e.virtual
+ e.params.cssMode || e.updateActiveIndex()
+ const y = void 0 === a ? e.activeIndex || 0 : a
+ let E, x, S, T
+ if (
+ ((E = e.rtlTranslate ? 'right' : e.isHorizontal() ? 'left' : 'top'),
+ 'auto' === l)
+ )
+ if (m) {
+ let t = e.size
+ t ||
+ (t = e.isHorizontal()
+ ? e.el.getBoundingClientRect().width
+ : e.el.getBoundingClientRect().height),
+ (x = Math.max(1, Math.ceil(t / m)))
+ } else x = 1
+ else x = l
+ n
+ ? ((S = Math.floor(x / 2) + r + u), (T = Math.floor(x / 2) + r + p))
+ : ((S = x + (r - 1) + u), (T = (d ? x : r) + p))
+ let M = y - T,
+ C = y + S
+ d || ((M = Math.max(M, 0)), (C = Math.min(C, v.length - 1)))
+ let P = (e.slidesGrid[M] || 0) - (e.slidesGrid[0] || 0)
+ function L() {
+ e.updateSlides(),
+ e.updateProgress(),
+ e.updateSlidesClasses(),
+ i('virtualUpdate')
+ }
+ if (
+ (d && y >= T
+ ? ((M -= T), n || (P += e.slidesGrid[0]))
+ : d && y < T && ((M = -T), n && (P += e.slidesGrid[0])),
+ Object.assign(e.virtual, {
+ from: M,
+ to: C,
+ offset: P,
+ slidesGrid: e.slidesGrid,
+ slidesBefore: T,
+ slidesAfter: S,
+ }),
+ h === M && f === C && !t)
+ )
+ return (
+ e.slidesGrid !== w &&
+ P !== b &&
+ e.slides.forEach((t) => {
+ t.style[E] = P - Math.abs(e.cssOverflowAdjustment()) + 'px'
+ }),
+ e.updateProgress(),
+ void i('virtualUpdate')
+ )
+ if (e.params.virtual.renderExternal)
+ return (
+ e.params.virtual.renderExternal.call(e, {
+ offset: P,
+ from: M,
+ to: C,
+ slides: (function () {
+ const e = []
+ for (let t = M; t <= C; t += 1) e.push(v[t])
+ return e
+ })(),
+ }),
+ void (e.params.virtual.renderExternalUpdate
+ ? L()
+ : i('virtualUpdate'))
+ )
+ const I = [],
+ z = [],
+ A = (e) => {
+ let t = e
+ return (
+ e < 0 ? (t = v.length + e) : t >= v.length && (t -= v.length), t
+ )
+ }
+ if (t)
+ e.slides
+ .filter((t) => t.matches(`.${e.params.slideClass}, swiper-slide`))
+ .forEach((e) => {
+ e.remove()
+ })
+ else
+ for (let t = h; t <= f; t += 1)
+ if (t < M || t > C) {
+ const s = A(t)
+ e.slides
+ .filter((t) =>
+ t.matches(
+ `.${e.params.slideClass}[data-swiper-slide-index="${s}"], swiper-slide[data-swiper-slide-index="${s}"]`
+ )
+ )
+ .forEach((e) => {
+ e.remove()
+ })
+ }
+ const $ = d ? -v.length : 0,
+ k = d ? 2 * v.length : v.length
+ for (let e = $; e < k; e += 1)
+ if (e >= M && e <= C) {
+ const s = A(e)
+ void 0 === f || t
+ ? z.push(s)
+ : (e > f && z.push(s), e < h && I.push(s))
+ }
+ if (
+ (z.forEach((t) => {
+ e.slidesEl.append(o(v[t], t))
+ }),
+ d)
+ )
+ for (let t = I.length - 1; t >= 0; t -= 1) {
+ const s = I[t]
+ e.slidesEl.prepend(o(v[s], s))
+ }
+ else
+ I.sort((e, t) => t - e),
+ I.forEach((t) => {
+ e.slidesEl.prepend(o(v[t], t))
+ })
+ g(e.slidesEl, '.swiper-slide, swiper-slide').forEach((t) => {
+ t.style[E] = P - Math.abs(e.cssOverflowAdjustment()) + 'px'
+ }),
+ L()
+ }
+ s('beforeInit', () => {
+ if (!e.params.virtual.enabled) return
+ let t
+ if (void 0 === e.passedParams.virtual.slides) {
+ const s = [...e.slidesEl.children].filter((t) =>
+ t.matches(`.${e.params.slideClass}, swiper-slide`)
+ )
+ s &&
+ s.length &&
+ ((e.virtual.slides = [...s]),
+ (t = !0),
+ s.forEach((t, s) => {
+ t.setAttribute('data-swiper-slide-index', s),
+ (e.virtual.cache[s] = t),
+ t.remove()
+ }))
+ }
+ t || (e.virtual.slides = e.params.virtual.slides),
+ e.classNames.push(`${e.params.containerModifierClass}virtual`),
+ (e.params.watchSlidesProgress = !0),
+ (e.originalParams.watchSlidesProgress = !0),
+ d(!1, !0)
+ }),
+ s('setTranslate', () => {
+ e.params.virtual.enabled &&
+ (e.params.cssMode && !e._immediateVirtual
+ ? (clearTimeout(r),
+ (r = setTimeout(() => {
+ d()
+ }, 100)))
+ : d())
+ }),
+ s('init update resize', () => {
+ e.params.virtual.enabled &&
+ e.params.cssMode &&
+ m(e.wrapperEl, '--swiper-virtual-size', `${e.virtualSize}px`)
+ }),
+ Object.assign(e.virtual, {
+ appendSlide: function (t) {
+ if ('object' == typeof t && 'length' in t)
+ for (let s = 0; s < t.length; s += 1)
+ t[s] && e.virtual.slides.push(t[s])
+ else e.virtual.slides.push(t)
+ d(!0)
+ },
+ prependSlide: function (t) {
+ const s = e.activeIndex
+ let a = s + 1,
+ i = 1
+ if (Array.isArray(t)) {
+ for (let s = 0; s < t.length; s += 1)
+ t[s] && e.virtual.slides.unshift(t[s])
+ ;(a = s + t.length), (i = t.length)
+ } else e.virtual.slides.unshift(t)
+ if (e.params.virtual.cache) {
+ const t = e.virtual.cache,
+ s = {}
+ Object.keys(t).forEach((e) => {
+ const a = t[e],
+ r = a.getAttribute('data-swiper-slide-index')
+ r &&
+ a.setAttribute(
+ 'data-swiper-slide-index',
+ parseInt(r, 10) + i
+ ),
+ (s[parseInt(e, 10) + i] = a)
+ }),
+ (e.virtual.cache = s)
+ }
+ d(!0), e.slideTo(a, 0)
+ },
+ removeSlide: function (t) {
+ if (null == t) return
+ let s = e.activeIndex
+ if (Array.isArray(t))
+ for (let a = t.length - 1; a >= 0; a -= 1)
+ e.params.virtual.cache &&
+ (delete e.virtual.cache[t[a]],
+ Object.keys(e.virtual.cache).forEach((s) => {
+ s > t &&
+ ((e.virtual.cache[s - 1] = e.virtual.cache[s]),
+ e.virtual.cache[s - 1].setAttribute(
+ 'data-swiper-slide-index',
+ s - 1
+ ),
+ delete e.virtual.cache[s])
+ })),
+ e.virtual.slides.splice(t[a], 1),
+ t[a] < s && (s -= 1),
+ (s = Math.max(s, 0))
+ else
+ e.params.virtual.cache &&
+ (delete e.virtual.cache[t],
+ Object.keys(e.virtual.cache).forEach((s) => {
+ s > t &&
+ ((e.virtual.cache[s - 1] = e.virtual.cache[s]),
+ e.virtual.cache[s - 1].setAttribute(
+ 'data-swiper-slide-index',
+ s - 1
+ ),
+ delete e.virtual.cache[s])
+ })),
+ e.virtual.slides.splice(t, 1),
+ t < s && (s -= 1),
+ (s = Math.max(s, 0))
+ d(!0), e.slideTo(s, 0)
+ },
+ removeAllSlides: function () {
+ ;(e.virtual.slides = []),
+ e.params.virtual.cache && (e.virtual.cache = {}),
+ d(!0),
+ e.slideTo(0, 0)
+ },
+ update: d,
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: i }) {
+ const n = a(),
+ l = r()
+ function o(t) {
+ if (!e.enabled) return
+ const { rtlTranslate: s } = e
+ let a = t
+ a.originalEvent && (a = a.originalEvent)
+ const r = a.keyCode || a.charCode,
+ o = e.params.keyboard.pageUpDown,
+ d = o && 33 === r,
+ c = o && 34 === r,
+ p = 37 === r,
+ u = 39 === r,
+ m = 38 === r,
+ h = 40 === r
+ if (
+ !e.allowSlideNext &&
+ ((e.isHorizontal() && u) || (e.isVertical() && h) || c)
+ )
+ return !1
+ if (
+ !e.allowSlidePrev &&
+ ((e.isHorizontal() && p) || (e.isVertical() && m) || d)
+ )
+ return !1
+ if (
+ !(
+ a.shiftKey ||
+ a.altKey ||
+ a.ctrlKey ||
+ a.metaKey ||
+ (n.activeElement &&
+ (n.activeElement.isContentEditable ||
+ (n.activeElement.nodeName &&
+ ('input' === n.activeElement.nodeName.toLowerCase() ||
+ 'textarea' === n.activeElement.nodeName.toLowerCase()))))
+ )
+ ) {
+ if (
+ e.params.keyboard.onlyInViewport &&
+ (d || c || p || u || m || h)
+ ) {
+ let t = !1
+ if (
+ x(e.el, `.${e.params.slideClass}, swiper-slide`).length > 0 &&
+ 0 === x(e.el, `.${e.params.slideActiveClass}`).length
+ )
+ return
+ const a = e.el,
+ i = a.clientWidth,
+ r = a.clientHeight,
+ n = l.innerWidth,
+ o = l.innerHeight,
+ d = b(a)
+ s && (d.left -= a.scrollLeft)
+ const c = [
+ [d.left, d.top],
+ [d.left + i, d.top],
+ [d.left, d.top + r],
+ [d.left + i, d.top + r],
+ ]
+ for (let e = 0; e < c.length; e += 1) {
+ const s = c[e]
+ if (s[0] >= 0 && s[0] <= n && s[1] >= 0 && s[1] <= o) {
+ if (0 === s[0] && 0 === s[1]) continue
+ t = !0
+ }
+ }
+ if (!t) return
+ }
+ e.isHorizontal()
+ ? ((d || c || p || u) &&
+ (a.preventDefault ? a.preventDefault() : (a.returnValue = !1)),
+ (((c || u) && !s) || ((d || p) && s)) && e.slideNext(),
+ (((d || p) && !s) || ((c || u) && s)) && e.slidePrev())
+ : ((d || c || m || h) &&
+ (a.preventDefault ? a.preventDefault() : (a.returnValue = !1)),
+ (c || h) && e.slideNext(),
+ (d || m) && e.slidePrev()),
+ i('keyPress', r)
+ }
+ }
+ function d() {
+ e.keyboard.enabled ||
+ (n.addEventListener('keydown', o), (e.keyboard.enabled = !0))
+ }
+ function c() {
+ e.keyboard.enabled &&
+ (n.removeEventListener('keydown', o), (e.keyboard.enabled = !1))
+ }
+ ;(e.keyboard = { enabled: !1 }),
+ t({ keyboard: { enabled: !1, onlyInViewport: !0, pageUpDown: !0 } }),
+ s('init', () => {
+ e.params.keyboard.enabled && d()
+ }),
+ s('destroy', () => {
+ e.keyboard.enabled && c()
+ }),
+ Object.assign(e.keyboard, { enable: d, disable: c })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: a }) {
+ const i = r()
+ let n
+ t({
+ mousewheel: {
+ enabled: !1,
+ releaseOnEdges: !1,
+ invert: !1,
+ forceToAxis: !1,
+ sensitivity: 1,
+ eventsTarget: 'container',
+ thresholdDelta: null,
+ thresholdTime: null,
+ noMousewheelClass: 'swiper-no-mousewheel',
+ },
+ }),
+ (e.mousewheel = { enabled: !1 })
+ let d,
+ c = o()
+ const p = []
+ function u() {
+ e.enabled && (e.mouseEntered = !0)
+ }
+ function m() {
+ e.enabled && (e.mouseEntered = !1)
+ }
+ function h(t) {
+ return (
+ !(
+ e.params.mousewheel.thresholdDelta &&
+ t.delta < e.params.mousewheel.thresholdDelta
+ ) &&
+ !(
+ e.params.mousewheel.thresholdTime &&
+ o() - c < e.params.mousewheel.thresholdTime
+ ) &&
+ ((t.delta >= 6 && o() - c < 60) ||
+ (t.direction < 0
+ ? (e.isEnd && !e.params.loop) ||
+ e.animating ||
+ (e.slideNext(), a('scroll', t.raw))
+ : (e.isBeginning && !e.params.loop) ||
+ e.animating ||
+ (e.slidePrev(), a('scroll', t.raw)),
+ (c = new i.Date().getTime()),
+ !1))
+ )
+ }
+ function f(t) {
+ let s = t,
+ i = !0
+ if (!e.enabled) return
+ if (t.target.closest(`.${e.params.mousewheel.noMousewheelClass}`))
+ return
+ const r = e.params.mousewheel
+ e.params.cssMode && s.preventDefault()
+ let c = e.el
+ 'container' !== e.params.mousewheel.eventsTarget &&
+ (c = document.querySelector(e.params.mousewheel.eventsTarget))
+ const u = c && c.contains(s.target)
+ if (!e.mouseEntered && !u && !r.releaseOnEdges) return !0
+ s.originalEvent && (s = s.originalEvent)
+ let m = 0
+ const f = e.rtlTranslate ? -1 : 1,
+ g = (function (e) {
+ let t = 0,
+ s = 0,
+ a = 0,
+ i = 0
+ return (
+ 'detail' in e && (s = e.detail),
+ 'wheelDelta' in e && (s = -e.wheelDelta / 120),
+ 'wheelDeltaY' in e && (s = -e.wheelDeltaY / 120),
+ 'wheelDeltaX' in e && (t = -e.wheelDeltaX / 120),
+ 'axis' in e && e.axis === e.HORIZONTAL_AXIS && ((t = s), (s = 0)),
+ (a = 10 * t),
+ (i = 10 * s),
+ 'deltaY' in e && (i = e.deltaY),
+ 'deltaX' in e && (a = e.deltaX),
+ e.shiftKey && !a && ((a = i), (i = 0)),
+ (a || i) &&
+ e.deltaMode &&
+ (1 === e.deltaMode
+ ? ((a *= 40), (i *= 40))
+ : ((a *= 800), (i *= 800))),
+ a && !t && (t = a < 1 ? -1 : 1),
+ i && !s && (s = i < 1 ? -1 : 1),
+ { spinX: t, spinY: s, pixelX: a, pixelY: i }
+ )
+ })(s)
+ if (r.forceToAxis)
+ if (e.isHorizontal()) {
+ if (!(Math.abs(g.pixelX) > Math.abs(g.pixelY))) return !0
+ m = -g.pixelX * f
+ } else {
+ if (!(Math.abs(g.pixelY) > Math.abs(g.pixelX))) return !0
+ m = -g.pixelY
+ }
+ else
+ m =
+ Math.abs(g.pixelX) > Math.abs(g.pixelY) ? -g.pixelX * f : -g.pixelY
+ if (0 === m) return !0
+ r.invert && (m = -m)
+ let v = e.getTranslate() + m * r.sensitivity
+ if (
+ (v >= e.minTranslate() && (v = e.minTranslate()),
+ v <= e.maxTranslate() && (v = e.maxTranslate()),
+ (i =
+ !!e.params.loop ||
+ !(v === e.minTranslate() || v === e.maxTranslate())),
+ i && e.params.nested && s.stopPropagation(),
+ e.params.freeMode && e.params.freeMode.enabled)
+ ) {
+ const t = { time: o(), delta: Math.abs(m), direction: Math.sign(m) },
+ i =
+ d &&
+ t.time < d.time + 500 &&
+ t.delta <= d.delta &&
+ t.direction === d.direction
+ if (!i) {
+ d = void 0
+ let o = e.getTranslate() + m * r.sensitivity
+ const c = e.isBeginning,
+ u = e.isEnd
+ if (
+ (o >= e.minTranslate() && (o = e.minTranslate()),
+ o <= e.maxTranslate() && (o = e.maxTranslate()),
+ e.setTransition(0),
+ e.setTranslate(o),
+ e.updateProgress(),
+ e.updateActiveIndex(),
+ e.updateSlidesClasses(),
+ ((!c && e.isBeginning) || (!u && e.isEnd)) &&
+ e.updateSlidesClasses(),
+ e.params.loop &&
+ e.loopFix({
+ direction: t.direction < 0 ? 'next' : 'prev',
+ byMousewheel: !0,
+ }),
+ e.params.freeMode.sticky)
+ ) {
+ clearTimeout(n), (n = void 0), p.length >= 15 && p.shift()
+ const s = p.length ? p[p.length - 1] : void 0,
+ a = p[0]
+ if (
+ (p.push(t),
+ s && (t.delta > s.delta || t.direction !== s.direction))
+ )
+ p.splice(0)
+ else if (
+ p.length >= 15 &&
+ t.time - a.time < 500 &&
+ a.delta - t.delta >= 1 &&
+ t.delta <= 6
+ ) {
+ const s = m > 0 ? 0.8 : 0.2
+ ;(d = t),
+ p.splice(0),
+ (n = l(() => {
+ !e.destroyed &&
+ e.params &&
+ e.slideToClosest(e.params.speed, !0, void 0, s)
+ }, 0))
+ }
+ n ||
+ (n = l(() => {
+ if (e.destroyed || !e.params) return
+ ;(d = t),
+ p.splice(0),
+ e.slideToClosest(e.params.speed, !0, void 0, 0.5)
+ }, 500))
+ }
+ if (
+ (i || a('scroll', s),
+ e.params.autoplay &&
+ e.params.autoplay.disableOnInteraction &&
+ e.autoplay.stop(),
+ r.releaseOnEdges &&
+ (o === e.minTranslate() || o === e.maxTranslate()))
+ )
+ return !0
+ }
+ } else {
+ const s = {
+ time: o(),
+ delta: Math.abs(m),
+ direction: Math.sign(m),
+ raw: t,
+ }
+ p.length >= 2 && p.shift()
+ const a = p.length ? p[p.length - 1] : void 0
+ if (
+ (p.push(s),
+ a
+ ? (s.direction !== a.direction ||
+ s.delta > a.delta ||
+ s.time > a.time + 150) &&
+ h(s)
+ : h(s),
+ (function (t) {
+ const s = e.params.mousewheel
+ if (t.direction < 0) {
+ if (e.isEnd && !e.params.loop && s.releaseOnEdges) return !0
+ } else if (e.isBeginning && !e.params.loop && s.releaseOnEdges)
+ return !0
+ return !1
+ })(s))
+ )
+ return !0
+ }
+ return s.preventDefault ? s.preventDefault() : (s.returnValue = !1), !1
+ }
+ function g(t) {
+ let s = e.el
+ 'container' !== e.params.mousewheel.eventsTarget &&
+ (s = document.querySelector(e.params.mousewheel.eventsTarget)),
+ s[t]('mouseenter', u),
+ s[t]('mouseleave', m),
+ s[t]('wheel', f)
+ }
+ function v() {
+ return e.params.cssMode
+ ? (e.wrapperEl.removeEventListener('wheel', f), !0)
+ : !e.mousewheel.enabled &&
+ (g('addEventListener'), (e.mousewheel.enabled = !0), !0)
+ }
+ function w() {
+ return e.params.cssMode
+ ? (e.wrapperEl.addEventListener(event, f), !0)
+ : !!e.mousewheel.enabled &&
+ (g('removeEventListener'), (e.mousewheel.enabled = !1), !0)
+ }
+ s('init', () => {
+ !e.params.mousewheel.enabled && e.params.cssMode && w(),
+ e.params.mousewheel.enabled && v()
+ }),
+ s('destroy', () => {
+ e.params.cssMode && v(), e.mousewheel.enabled && w()
+ }),
+ Object.assign(e.mousewheel, { enable: v, disable: w })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: a }) {
+ function i(t) {
+ let s
+ return t &&
+ 'string' == typeof t &&
+ e.isElement &&
+ ((s = e.el.querySelector(t) || e.hostEl.querySelector(t)), s)
+ ? s
+ : (t &&
+ ('string' == typeof t && (s = [...document.querySelectorAll(t)]),
+ e.params.uniqueNavElements &&
+ 'string' == typeof t &&
+ s &&
+ s.length > 1 &&
+ 1 === e.el.querySelectorAll(t).length
+ ? (s = e.el.querySelector(t))
+ : s && 1 === s.length && (s = s[0])),
+ t && !s ? t : s)
+ }
+ function r(t, s) {
+ const a = e.params.navigation
+ ;(t = M(t)).forEach((t) => {
+ t &&
+ (t.classList[s ? 'add' : 'remove'](...a.disabledClass.split(' ')),
+ 'BUTTON' === t.tagName && (t.disabled = s),
+ e.params.watchOverflow &&
+ e.enabled &&
+ t.classList[e.isLocked ? 'add' : 'remove'](a.lockClass))
+ })
+ }
+ function n() {
+ const { nextEl: t, prevEl: s } = e.navigation
+ if (e.params.loop) return r(s, !1), void r(t, !1)
+ r(s, e.isBeginning && !e.params.rewind),
+ r(t, e.isEnd && !e.params.rewind)
+ }
+ function l(t) {
+ t.preventDefault(),
+ (!e.isBeginning || e.params.loop || e.params.rewind) &&
+ (e.slidePrev(), a('navigationPrev'))
+ }
+ function o(t) {
+ t.preventDefault(),
+ (!e.isEnd || e.params.loop || e.params.rewind) &&
+ (e.slideNext(), a('navigationNext'))
+ }
+ function d() {
+ const t = e.params.navigation
+ if (
+ ((e.params.navigation = le(
+ e,
+ e.originalParams.navigation,
+ e.params.navigation,
+ { nextEl: 'swiper-button-next', prevEl: 'swiper-button-prev' }
+ )),
+ !t.nextEl && !t.prevEl)
+ )
+ return
+ let s = i(t.nextEl),
+ a = i(t.prevEl)
+ Object.assign(e.navigation, { nextEl: s, prevEl: a }),
+ (s = M(s)),
+ (a = M(a))
+ const r = (s, a) => {
+ if (s) {
+ if (
+ t.addIcons &&
+ s.matches('.swiper-button-next,.swiper-button-prev') &&
+ !s.querySelector('svg')
+ ) {
+ const e = document.createElement('div')
+ P(e, oe), s.appendChild(e.querySelector('svg')), e.remove()
+ }
+ s.addEventListener('click', 'next' === a ? o : l)
+ }
+ !e.enabled && s && s.classList.add(...t.lockClass.split(' '))
+ }
+ s.forEach((e) => r(e, 'next')), a.forEach((e) => r(e, 'prev'))
+ }
+ function c() {
+ let { nextEl: t, prevEl: s } = e.navigation
+ ;(t = M(t)), (s = M(s))
+ const a = (t, s) => {
+ t.removeEventListener('click', 'next' === s ? o : l),
+ t.classList.remove(...e.params.navigation.disabledClass.split(' '))
+ }
+ t.forEach((e) => a(e, 'next')), s.forEach((e) => a(e, 'prev'))
+ }
+ t({
+ navigation: {
+ nextEl: null,
+ prevEl: null,
+ addIcons: !0,
+ hideOnClick: !1,
+ disabledClass: 'swiper-button-disabled',
+ hiddenClass: 'swiper-button-hidden',
+ lockClass: 'swiper-button-lock',
+ navigationDisabledClass: 'swiper-navigation-disabled',
+ },
+ }),
+ (e.navigation = { nextEl: null, prevEl: null, arrowSvg: oe }),
+ s('init', () => {
+ !1 === e.params.navigation.enabled ? p() : (d(), n())
+ }),
+ s('toEdge fromEdge lock unlock', () => {
+ n()
+ }),
+ s('destroy', () => {
+ c()
+ }),
+ s('enable disable', () => {
+ let { nextEl: t, prevEl: s } = e.navigation
+ ;(t = M(t)),
+ (s = M(s)),
+ e.enabled
+ ? n()
+ : [...t, ...s]
+ .filter((e) => !!e)
+ .forEach((t) =>
+ t.classList.add(e.params.navigation.lockClass)
+ )
+ }),
+ s('click', (t, s) => {
+ let { nextEl: i, prevEl: r } = e.navigation
+ ;(i = M(i)), (r = M(r))
+ const n = s.target
+ let l = r.includes(n) || i.includes(n)
+ if (e.isElement && !l) {
+ const e = s.path || (s.composedPath && s.composedPath())
+ e && (l = e.find((e) => i.includes(e) || r.includes(e)))
+ }
+ if (e.params.navigation.hideOnClick && !l) {
+ if (
+ e.pagination &&
+ e.params.pagination &&
+ e.params.pagination.clickable &&
+ (e.pagination.el === n || e.pagination.el.contains(n))
+ )
+ return
+ let t
+ i.length
+ ? (t = i[0].classList.contains(e.params.navigation.hiddenClass))
+ : r.length &&
+ (t = r[0].classList.contains(e.params.navigation.hiddenClass)),
+ a(!0 === t ? 'navigationShow' : 'navigationHide'),
+ [...i, ...r]
+ .filter((e) => !!e)
+ .forEach((t) =>
+ t.classList.toggle(e.params.navigation.hiddenClass)
+ )
+ }
+ })
+ const p = () => {
+ e.el.classList.add(
+ ...e.params.navigation.navigationDisabledClass.split(' ')
+ ),
+ c()
+ }
+ Object.assign(e.navigation, {
+ enable: () => {
+ e.el.classList.remove(
+ ...e.params.navigation.navigationDisabledClass.split(' ')
+ ),
+ d(),
+ n()
+ },
+ disable: p,
+ update: n,
+ init: d,
+ destroy: c,
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: a }) {
+ const i = 'swiper-pagination'
+ let r
+ t({
+ pagination: {
+ el: null,
+ bulletElement: 'span',
+ clickable: !1,
+ hideOnClick: !1,
+ renderBullet: null,
+ renderProgressbar: null,
+ renderFraction: null,
+ renderCustom: null,
+ progressbarOpposite: !1,
+ type: 'bullets',
+ dynamicBullets: !1,
+ dynamicMainBullets: 1,
+ formatFractionCurrent: (e) => e,
+ formatFractionTotal: (e) => e,
+ bulletClass: `${i}-bullet`,
+ bulletActiveClass: `${i}-bullet-active`,
+ modifierClass: `${i}-`,
+ currentClass: `${i}-current`,
+ totalClass: `${i}-total`,
+ hiddenClass: `${i}-hidden`,
+ progressbarFillClass: `${i}-progressbar-fill`,
+ progressbarOppositeClass: `${i}-progressbar-opposite`,
+ clickableClass: `${i}-clickable`,
+ lockClass: `${i}-lock`,
+ horizontalClass: `${i}-horizontal`,
+ verticalClass: `${i}-vertical`,
+ paginationDisabledClass: `${i}-disabled`,
+ },
+ }),
+ (e.pagination = { el: null, bullets: [] })
+ let n = 0
+ function l() {
+ return (
+ !e.params.pagination.el ||
+ !e.pagination.el ||
+ (Array.isArray(e.pagination.el) && 0 === e.pagination.el.length)
+ )
+ }
+ function o(t, s) {
+ const { bulletActiveClass: a } = e.params.pagination
+ t &&
+ (t = t[('prev' === s ? 'previous' : 'next') + 'ElementSibling']) &&
+ (t.classList.add(`${a}-${s}`),
+ (t = t[('prev' === s ? 'previous' : 'next') + 'ElementSibling']) &&
+ t.classList.add(`${a}-${s}-${s}`))
+ }
+ function d(t) {
+ const s = t.target.closest(de(e.params.pagination.bulletClass))
+ if (!s) return
+ t.preventDefault()
+ const a = E(s) * e.params.slidesPerGroup
+ if (e.params.loop) {
+ if (e.realIndex === a) return
+ const t =
+ ((i = e.realIndex),
+ (r = a),
+ (n = e.slides.length),
+ (r %= n) === 1 + (i %= n)
+ ? 'next'
+ : r === i - 1
+ ? 'previous'
+ : void 0)
+ 'next' === t
+ ? e.slideNext()
+ : 'previous' === t
+ ? e.slidePrev()
+ : e.slideToLoop(a)
+ } else e.slideTo(a)
+ var i, r, n
+ }
+ function c() {
+ const t = e.rtl,
+ s = e.params.pagination
+ if (l()) return
+ let i,
+ d,
+ c = e.pagination.el
+ c = M(c)
+ const p =
+ e.virtual && e.params.virtual.enabled
+ ? e.virtual.slides.length
+ : e.slides.length,
+ u = e.params.loop
+ ? Math.ceil(p / e.params.slidesPerGroup)
+ : e.snapGrid.length
+ if (
+ (e.params.loop
+ ? ((d = e.previousRealIndex || 0),
+ (i =
+ e.params.slidesPerGroup > 1
+ ? Math.floor(e.realIndex / e.params.slidesPerGroup)
+ : e.realIndex))
+ : void 0 !== e.snapIndex
+ ? ((i = e.snapIndex), (d = e.previousSnapIndex))
+ : ((d = e.previousIndex || 0), (i = e.activeIndex || 0)),
+ 'bullets' === s.type &&
+ e.pagination.bullets &&
+ e.pagination.bullets.length > 0)
+ ) {
+ const a = e.pagination.bullets
+ let l, p, u
+ if (
+ (s.dynamicBullets &&
+ ((r = T(a[0], e.isHorizontal() ? 'width' : 'height', !0)),
+ c.forEach((t) => {
+ t.style[e.isHorizontal() ? 'width' : 'height'] =
+ r * (s.dynamicMainBullets + 4) + 'px'
+ }),
+ s.dynamicMainBullets > 1 &&
+ void 0 !== d &&
+ ((n += i - (d || 0)),
+ n > s.dynamicMainBullets - 1
+ ? (n = s.dynamicMainBullets - 1)
+ : n < 0 && (n = 0)),
+ (l = Math.max(i - n, 0)),
+ (p = l + (Math.min(a.length, s.dynamicMainBullets) - 1)),
+ (u = (p + l) / 2)),
+ a.forEach((e) => {
+ const t = [
+ ...[
+ '',
+ '-next',
+ '-next-next',
+ '-prev',
+ '-prev-prev',
+ '-main',
+ ].map((e) => `${s.bulletActiveClass}${e}`),
+ ]
+ .map((e) =>
+ 'string' == typeof e && e.includes(' ') ? e.split(' ') : e
+ )
+ .flat()
+ e.classList.remove(...t)
+ }),
+ c.length > 1)
+ )
+ a.forEach((t) => {
+ const a = E(t)
+ a === i
+ ? t.classList.add(...s.bulletActiveClass.split(' '))
+ : e.isElement && t.setAttribute('part', 'bullet'),
+ s.dynamicBullets &&
+ (a >= l &&
+ a <= p &&
+ t.classList.add(
+ ...`${s.bulletActiveClass}-main`.split(' ')
+ ),
+ a === l && o(t, 'prev'),
+ a === p && o(t, 'next'))
+ })
+ else {
+ const t = a[i]
+ if (
+ (t && t.classList.add(...s.bulletActiveClass.split(' ')),
+ e.isElement &&
+ a.forEach((e, t) => {
+ e.setAttribute('part', t === i ? 'bullet-active' : 'bullet')
+ }),
+ s.dynamicBullets)
+ ) {
+ const e = a[l],
+ t = a[p]
+ for (let e = l; e <= p; e += 1)
+ a[e] &&
+ a[e].classList.add(
+ ...`${s.bulletActiveClass}-main`.split(' ')
+ )
+ o(e, 'prev'), o(t, 'next')
+ }
+ }
+ if (s.dynamicBullets) {
+ const i = Math.min(a.length, s.dynamicMainBullets + 4),
+ n = (r * i - r) / 2 - u * r,
+ l = t ? 'right' : 'left'
+ a.forEach((t) => {
+ t.style[e.isHorizontal() ? l : 'top'] = `${n}px`
+ })
+ }
+ }
+ c.forEach((t, r) => {
+ if (
+ ('fraction' === s.type &&
+ (t.querySelectorAll(de(s.currentClass)).forEach((e) => {
+ e.textContent = s.formatFractionCurrent(i + 1)
+ }),
+ t.querySelectorAll(de(s.totalClass)).forEach((e) => {
+ e.textContent = s.formatFractionTotal(u)
+ })),
+ 'progressbar' === s.type)
+ ) {
+ let a
+ a = s.progressbarOpposite
+ ? e.isHorizontal()
+ ? 'vertical'
+ : 'horizontal'
+ : e.isHorizontal()
+ ? 'horizontal'
+ : 'vertical'
+ const r = (i + 1) / u
+ let n = 1,
+ l = 1
+ 'horizontal' === a ? (n = r) : (l = r),
+ t.querySelectorAll(de(s.progressbarFillClass)).forEach((t) => {
+ ;(t.style.transform = `translate3d(0,0,0) scaleX(${n}) scaleY(${l})`),
+ (t.style.transitionDuration = `${e.params.speed}ms`)
+ })
+ }
+ 'custom' === s.type && s.renderCustom
+ ? (P(t, s.renderCustom(e, i + 1, u)),
+ 0 === r && a('paginationRender', t))
+ : (0 === r && a('paginationRender', t), a('paginationUpdate', t)),
+ e.params.watchOverflow &&
+ e.enabled &&
+ t.classList[e.isLocked ? 'add' : 'remove'](s.lockClass)
+ })
+ }
+ function p() {
+ const t = e.params.pagination
+ if (l()) return
+ const s =
+ e.virtual && e.params.virtual.enabled
+ ? e.virtual.slides.length
+ : e.grid && e.params.grid.rows > 1
+ ? e.slides.length / Math.ceil(e.params.grid.rows)
+ : e.slides.length
+ let i = e.pagination.el
+ i = M(i)
+ let r = ''
+ if ('bullets' === t.type) {
+ let a = e.params.loop
+ ? Math.ceil(s / e.params.slidesPerGroup)
+ : e.snapGrid.length
+ e.params.freeMode && e.params.freeMode.enabled && a > s && (a = s)
+ for (let s = 0; s < a; s += 1)
+ t.renderBullet
+ ? (r += t.renderBullet.call(e, s, t.bulletClass))
+ : (r += `<${t.bulletElement} ${
+ e.isElement ? 'part="bullet"' : ''
+ } class="${t.bulletClass}">${t.bulletElement}>`)
+ }
+ 'fraction' === t.type &&
+ (r = t.renderFraction
+ ? t.renderFraction.call(e, t.currentClass, t.totalClass)
+ : ` / `),
+ 'progressbar' === t.type &&
+ (r = t.renderProgressbar
+ ? t.renderProgressbar.call(e, t.progressbarFillClass)
+ : ``),
+ (e.pagination.bullets = []),
+ i.forEach((s) => {
+ 'custom' !== t.type && P(s, r || ''),
+ 'bullets' === t.type &&
+ e.pagination.bullets.push(
+ ...s.querySelectorAll(de(t.bulletClass))
+ )
+ }),
+ 'custom' !== t.type && a('paginationRender', i[0])
+ }
+ function u() {
+ e.params.pagination = le(
+ e,
+ e.originalParams.pagination,
+ e.params.pagination,
+ { el: 'swiper-pagination' }
+ )
+ const t = e.params.pagination
+ if (!t.el) return
+ let s
+ 'string' == typeof t.el &&
+ e.isElement &&
+ (s = e.el.querySelector(t.el)),
+ s ||
+ 'string' != typeof t.el ||
+ (s = [...document.querySelectorAll(t.el)]),
+ s || (s = t.el),
+ s &&
+ 0 !== s.length &&
+ (e.params.uniqueNavElements &&
+ 'string' == typeof t.el &&
+ Array.isArray(s) &&
+ s.length > 1 &&
+ ((s = [...e.el.querySelectorAll(t.el)]),
+ s.length > 1 && (s = s.find((t) => x(t, '.swiper')[0] === e.el))),
+ Array.isArray(s) && 1 === s.length && (s = s[0]),
+ Object.assign(e.pagination, { el: s }),
+ (s = M(s)),
+ s.forEach((s) => {
+ 'bullets' === t.type &&
+ t.clickable &&
+ s.classList.add(...(t.clickableClass || '').split(' ')),
+ s.classList.add(t.modifierClass + t.type),
+ s.classList.add(
+ e.isHorizontal() ? t.horizontalClass : t.verticalClass
+ ),
+ 'bullets' === t.type &&
+ t.dynamicBullets &&
+ (s.classList.add(`${t.modifierClass}${t.type}-dynamic`),
+ (n = 0),
+ t.dynamicMainBullets < 1 && (t.dynamicMainBullets = 1)),
+ 'progressbar' === t.type &&
+ t.progressbarOpposite &&
+ s.classList.add(t.progressbarOppositeClass),
+ t.clickable && s.addEventListener('click', d),
+ e.enabled || s.classList.add(t.lockClass)
+ }))
+ }
+ function m() {
+ const t = e.params.pagination
+ if (l()) return
+ let s = e.pagination.el
+ s &&
+ ((s = M(s)),
+ s.forEach((s) => {
+ s.classList.remove(t.hiddenClass),
+ s.classList.remove(t.modifierClass + t.type),
+ s.classList.remove(
+ e.isHorizontal() ? t.horizontalClass : t.verticalClass
+ ),
+ t.clickable &&
+ (s.classList.remove(...(t.clickableClass || '').split(' ')),
+ s.removeEventListener('click', d))
+ })),
+ e.pagination.bullets &&
+ e.pagination.bullets.forEach((e) =>
+ e.classList.remove(...t.bulletActiveClass.split(' '))
+ )
+ }
+ s('changeDirection', () => {
+ if (!e.pagination || !e.pagination.el) return
+ const t = e.params.pagination
+ let { el: s } = e.pagination
+ ;(s = M(s)),
+ s.forEach((s) => {
+ s.classList.remove(t.horizontalClass, t.verticalClass),
+ s.classList.add(
+ e.isHorizontal() ? t.horizontalClass : t.verticalClass
+ )
+ })
+ }),
+ s('init', () => {
+ !1 === e.params.pagination.enabled ? h() : (u(), p(), c())
+ }),
+ s('activeIndexChange', () => {
+ void 0 === e.snapIndex && c()
+ }),
+ s('snapIndexChange', () => {
+ c()
+ }),
+ s('snapGridLengthChange', () => {
+ p(), c()
+ }),
+ s('destroy', () => {
+ m()
+ }),
+ s('enable disable', () => {
+ let { el: t } = e.pagination
+ t &&
+ ((t = M(t)),
+ t.forEach((t) =>
+ t.classList[e.enabled ? 'remove' : 'add'](
+ e.params.pagination.lockClass
+ )
+ ))
+ }),
+ s('lock unlock', () => {
+ c()
+ }),
+ s('click', (t, s) => {
+ const i = s.target,
+ r = M(e.pagination.el)
+ if (
+ e.params.pagination.el &&
+ e.params.pagination.hideOnClick &&
+ r &&
+ r.length > 0 &&
+ !i.classList.contains(e.params.pagination.bulletClass)
+ ) {
+ if (
+ e.navigation &&
+ ((e.navigation.nextEl && i === e.navigation.nextEl) ||
+ (e.navigation.prevEl && i === e.navigation.prevEl))
+ )
+ return
+ const t = r[0].classList.contains(e.params.pagination.hiddenClass)
+ a(!0 === t ? 'paginationShow' : 'paginationHide'),
+ r.forEach((t) =>
+ t.classList.toggle(e.params.pagination.hiddenClass)
+ )
+ }
+ })
+ const h = () => {
+ e.el.classList.add(e.params.pagination.paginationDisabledClass)
+ let { el: t } = e.pagination
+ t &&
+ ((t = M(t)),
+ t.forEach((t) =>
+ t.classList.add(e.params.pagination.paginationDisabledClass)
+ )),
+ m()
+ }
+ Object.assign(e.pagination, {
+ enable: () => {
+ e.el.classList.remove(e.params.pagination.paginationDisabledClass)
+ let { el: t } = e.pagination
+ t &&
+ ((t = M(t)),
+ t.forEach((t) =>
+ t.classList.remove(e.params.pagination.paginationDisabledClass)
+ )),
+ u(),
+ p(),
+ c()
+ },
+ disable: h,
+ render: p,
+ update: c,
+ init: u,
+ destroy: m,
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: i }) {
+ const r = a()
+ let o,
+ d,
+ c,
+ p,
+ u = !1,
+ m = null,
+ h = null
+ function f() {
+ if (!e.params.scrollbar.el || !e.scrollbar.el) return
+ const { scrollbar: t, rtlTranslate: s } = e,
+ { dragEl: a, el: i } = t,
+ r = e.params.scrollbar,
+ n = e.params.loop ? e.progressLoop : e.progress
+ let l = d,
+ o = (c - d) * n
+ s
+ ? ((o = -o),
+ o > 0 ? ((l = d - o), (o = 0)) : -o + d > c && (l = c + o))
+ : o < 0
+ ? ((l = d + o), (o = 0))
+ : o + d > c && (l = c - o),
+ e.isHorizontal()
+ ? ((a.style.transform = `translate3d(${o}px, 0, 0)`),
+ (a.style.width = `${l}px`))
+ : ((a.style.transform = `translate3d(0px, ${o}px, 0)`),
+ (a.style.height = `${l}px`)),
+ r.hide &&
+ (clearTimeout(m),
+ (i.style.opacity = 1),
+ (m = setTimeout(() => {
+ ;(i.style.opacity = 0), (i.style.transitionDuration = '400ms')
+ }, 1e3)))
+ }
+ function g() {
+ if (!e.params.scrollbar.el || !e.scrollbar.el) return
+ const { scrollbar: t } = e,
+ { dragEl: s, el: a } = t
+ ;(s.style.width = ''),
+ (s.style.height = ''),
+ (c = e.isHorizontal() ? a.offsetWidth : a.offsetHeight),
+ (p =
+ e.size /
+ (e.virtualSize +
+ e.params.slidesOffsetBefore -
+ (e.params.centeredSlides ? e.snapGrid[0] : 0))),
+ (d =
+ 'auto' === e.params.scrollbar.dragSize
+ ? c * p
+ : parseInt(e.params.scrollbar.dragSize, 10)),
+ e.isHorizontal()
+ ? (s.style.width = `${d}px`)
+ : (s.style.height = `${d}px`),
+ (a.style.display = p >= 1 ? 'none' : ''),
+ e.params.scrollbar.hide && (a.style.opacity = 0),
+ e.params.watchOverflow &&
+ e.enabled &&
+ t.el.classList[e.isLocked ? 'add' : 'remove'](
+ e.params.scrollbar.lockClass
+ )
+ }
+ function v(t) {
+ return e.isHorizontal() ? t.clientX : t.clientY
+ }
+ function y(t) {
+ const { scrollbar: s, rtlTranslate: a } = e,
+ { el: i } = s
+ let r
+ ;(r =
+ (v(t) -
+ b(i)[e.isHorizontal() ? 'left' : 'top'] -
+ (null !== o ? o : d / 2)) /
+ (c - d)),
+ (r = Math.max(Math.min(r, 1), 0)),
+ a && (r = 1 - r)
+ const n = e.minTranslate() + (e.maxTranslate() - e.minTranslate()) * r
+ e.updateProgress(n),
+ e.setTranslate(n),
+ e.updateActiveIndex(),
+ e.updateSlidesClasses()
+ }
+ function E(t) {
+ const s = e.params.scrollbar,
+ { scrollbar: a, wrapperEl: r } = e,
+ { el: n, dragEl: l } = a
+ ;(u = !0),
+ (o =
+ t.target === l
+ ? v(t) -
+ t.target.getBoundingClientRect()[
+ e.isHorizontal() ? 'left' : 'top'
+ ]
+ : null),
+ t.preventDefault(),
+ t.stopPropagation(),
+ (r.style.transitionDuration = '100ms'),
+ (l.style.transitionDuration = '100ms'),
+ y(t),
+ clearTimeout(h),
+ (n.style.transitionDuration = '0ms'),
+ s.hide && (n.style.opacity = 1),
+ e.params.cssMode && (e.wrapperEl.style['scroll-snap-type'] = 'none'),
+ i('scrollbarDragStart', t)
+ }
+ function x(t) {
+ const { scrollbar: s, wrapperEl: a } = e,
+ { el: r, dragEl: n } = s
+ u &&
+ (t.preventDefault && t.cancelable
+ ? t.preventDefault()
+ : (t.returnValue = !1),
+ y(t),
+ (a.style.transitionDuration = '0ms'),
+ (r.style.transitionDuration = '0ms'),
+ (n.style.transitionDuration = '0ms'),
+ i('scrollbarDragMove', t))
+ }
+ function S(t) {
+ const s = e.params.scrollbar,
+ { scrollbar: a, wrapperEl: r } = e,
+ { el: n } = a
+ u &&
+ ((u = !1),
+ e.params.cssMode &&
+ ((e.wrapperEl.style['scroll-snap-type'] = ''),
+ (r.style.transitionDuration = '')),
+ s.hide &&
+ (clearTimeout(h),
+ (h = l(() => {
+ ;(n.style.opacity = 0), (n.style.transitionDuration = '400ms')
+ }, 1e3))),
+ i('scrollbarDragEnd', t),
+ s.snapOnRelease && e.slideToClosest())
+ }
+ function T(t) {
+ const { scrollbar: s, params: a } = e,
+ i = s.el
+ if (!i) return
+ const n = i,
+ l = !!a.passiveListeners && { passive: !1, capture: !1 },
+ o = !!a.passiveListeners && { passive: !0, capture: !1 }
+ if (!n) return
+ const d = 'on' === t ? 'addEventListener' : 'removeEventListener'
+ n[d]('pointerdown', E, l),
+ r[d]('pointermove', x, l),
+ r[d]('pointerup', S, o)
+ }
+ function C() {
+ const { scrollbar: t, el: s } = e
+ e.params.scrollbar = le(
+ e,
+ e.originalParams.scrollbar,
+ e.params.scrollbar,
+ { el: 'swiper-scrollbar' }
+ )
+ const a = e.params.scrollbar
+ if (!a.el) return
+ let i, l
+ if (
+ ('string' == typeof a.el &&
+ e.isElement &&
+ (i = e.el.querySelector(a.el)),
+ i || 'string' != typeof a.el)
+ )
+ i || (i = a.el)
+ else if (((i = r.querySelectorAll(a.el)), !i.length)) return
+ e.params.uniqueNavElements &&
+ 'string' == typeof a.el &&
+ i.length > 1 &&
+ 1 === s.querySelectorAll(a.el).length &&
+ (i = s.querySelector(a.el)),
+ i.length > 0 && (i = i[0]),
+ i.classList.add(
+ e.isHorizontal() ? a.horizontalClass : a.verticalClass
+ ),
+ i &&
+ ((l = i.querySelector(de(e.params.scrollbar.dragClass))),
+ l || ((l = w('div', e.params.scrollbar.dragClass)), i.append(l))),
+ Object.assign(t, { el: i, dragEl: l }),
+ a.draggable && e.params.scrollbar.el && e.scrollbar.el && T('on'),
+ i &&
+ i.classList[e.enabled ? 'remove' : 'add'](
+ ...n(e.params.scrollbar.lockClass)
+ )
+ }
+ function P() {
+ const t = e.params.scrollbar,
+ s = e.scrollbar.el
+ s &&
+ s.classList.remove(
+ ...n(e.isHorizontal() ? t.horizontalClass : t.verticalClass)
+ ),
+ e.params.scrollbar.el && e.scrollbar.el && T('off')
+ }
+ t({
+ scrollbar: {
+ el: null,
+ dragSize: 'auto',
+ hide: !1,
+ draggable: !1,
+ snapOnRelease: !0,
+ lockClass: 'swiper-scrollbar-lock',
+ dragClass: 'swiper-scrollbar-drag',
+ scrollbarDisabledClass: 'swiper-scrollbar-disabled',
+ horizontalClass: 'swiper-scrollbar-horizontal',
+ verticalClass: 'swiper-scrollbar-vertical',
+ },
+ }),
+ (e.scrollbar = { el: null, dragEl: null }),
+ s('changeDirection', () => {
+ if (!e.scrollbar || !e.scrollbar.el) return
+ const t = e.params.scrollbar
+ let { el: s } = e.scrollbar
+ ;(s = M(s)),
+ s.forEach((s) => {
+ s.classList.remove(t.horizontalClass, t.verticalClass),
+ s.classList.add(
+ e.isHorizontal() ? t.horizontalClass : t.verticalClass
+ )
+ })
+ }),
+ s('init', () => {
+ !1 === e.params.scrollbar.enabled ? L() : (C(), g(), f())
+ }),
+ s('update resize observerUpdate lock unlock changeDirection', () => {
+ g()
+ }),
+ s('setTranslate', () => {
+ f()
+ }),
+ s('setTransition', (t, s) => {
+ !(function (t) {
+ e.params.scrollbar.el &&
+ e.scrollbar.el &&
+ (e.scrollbar.dragEl.style.transitionDuration = `${t}ms`)
+ })(s)
+ }),
+ s('enable disable', () => {
+ const { el: t } = e.scrollbar
+ t &&
+ t.classList[e.enabled ? 'remove' : 'add'](
+ ...n(e.params.scrollbar.lockClass)
+ )
+ }),
+ s('destroy', () => {
+ P()
+ })
+ const L = () => {
+ e.el.classList.add(...n(e.params.scrollbar.scrollbarDisabledClass)),
+ e.scrollbar.el &&
+ e.scrollbar.el.classList.add(
+ ...n(e.params.scrollbar.scrollbarDisabledClass)
+ ),
+ P()
+ }
+ Object.assign(e.scrollbar, {
+ enable: () => {
+ e.el.classList.remove(
+ ...n(e.params.scrollbar.scrollbarDisabledClass)
+ ),
+ e.scrollbar.el &&
+ e.scrollbar.el.classList.remove(
+ ...n(e.params.scrollbar.scrollbarDisabledClass)
+ ),
+ C(),
+ g(),
+ f()
+ },
+ disable: L,
+ updateSize: g,
+ setTranslate: f,
+ init: C,
+ destroy: P,
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({ parallax: { enabled: !1 } })
+ const a =
+ '[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y], [data-swiper-parallax-opacity], [data-swiper-parallax-scale]',
+ i = (t, s) => {
+ const { rtl: a } = e,
+ i = a ? -1 : 1,
+ r = t.getAttribute('data-swiper-parallax') || '0'
+ let n = t.getAttribute('data-swiper-parallax-x'),
+ l = t.getAttribute('data-swiper-parallax-y')
+ const o = t.getAttribute('data-swiper-parallax-scale'),
+ d = t.getAttribute('data-swiper-parallax-opacity'),
+ c = t.getAttribute('data-swiper-parallax-rotate')
+ if (
+ (n || l
+ ? ((n = n || '0'), (l = l || '0'))
+ : e.isHorizontal()
+ ? ((n = r), (l = '0'))
+ : ((l = r), (n = '0')),
+ (n =
+ n.indexOf('%') >= 0
+ ? parseInt(n, 10) * s * i + '%'
+ : n * s * i + 'px'),
+ (l =
+ l.indexOf('%') >= 0 ? parseInt(l, 10) * s + '%' : l * s + 'px'),
+ null != d)
+ ) {
+ const e = d - (d - 1) * (1 - Math.abs(s))
+ t.style.opacity = e
+ }
+ let p = `translate3d(${n}, ${l}, 0px)`
+ if (null != o) {
+ p += ` scale(${o - (o - 1) * (1 - Math.abs(s))})`
+ }
+ if (c && null != c) {
+ p += ` rotate(${c * s * -1}deg)`
+ }
+ t.style.transform = p
+ },
+ r = () => {
+ const {
+ el: t,
+ slides: s,
+ progress: r,
+ snapGrid: n,
+ isElement: l,
+ } = e,
+ o = g(t, a)
+ e.isElement && o.push(...g(e.hostEl, a)),
+ o.forEach((e) => {
+ i(e, r)
+ }),
+ s.forEach((t, s) => {
+ let l = t.progress
+ e.params.slidesPerGroup > 1 &&
+ 'auto' !== e.params.slidesPerView &&
+ (l += Math.ceil(s / 2) - r * (n.length - 1)),
+ (l = Math.min(Math.max(l, -1), 1)),
+ t
+ .querySelectorAll(`${a}, [data-swiper-parallax-rotate]`)
+ .forEach((e) => {
+ i(e, l)
+ })
+ })
+ }
+ s('beforeInit', () => {
+ e.params.parallax.enabled &&
+ ((e.params.watchSlidesProgress = !0),
+ (e.originalParams.watchSlidesProgress = !0))
+ }),
+ s('init', () => {
+ e.params.parallax.enabled && r()
+ }),
+ s('setTranslate', () => {
+ e.params.parallax.enabled && r()
+ }),
+ s('setTransition', (t, s) => {
+ e.params.parallax.enabled &&
+ ((t = e.params.speed) => {
+ const { el: s, hostEl: i } = e,
+ r = [...s.querySelectorAll(a)]
+ e.isElement && r.push(...i.querySelectorAll(a)),
+ r.forEach((e) => {
+ let s =
+ parseInt(
+ e.getAttribute('data-swiper-parallax-duration'),
+ 10
+ ) || t
+ 0 === t && (s = 0), (e.style.transitionDuration = `${s}ms`)
+ })
+ })(s)
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: a }) {
+ const i = r()
+ t({
+ zoom: {
+ enabled: !1,
+ limitToOriginalSize: !1,
+ maxRatio: 3,
+ minRatio: 1,
+ panOnMouseMove: !1,
+ toggle: !0,
+ containerClass: 'swiper-zoom-container',
+ zoomedSlideClass: 'swiper-slide-zoomed',
+ },
+ }),
+ (e.zoom = { enabled: !1 })
+ let n,
+ l,
+ o = 1,
+ c = !1,
+ p = !1,
+ u = { x: 0, y: 0 }
+ const m = [],
+ h = {
+ originX: 0,
+ originY: 0,
+ slideEl: void 0,
+ slideWidth: void 0,
+ slideHeight: void 0,
+ imageEl: void 0,
+ imageWrapEl: void 0,
+ maxRatio: 3,
+ },
+ f = {
+ isTouched: void 0,
+ isMoved: void 0,
+ currentX: void 0,
+ currentY: void 0,
+ minX: void 0,
+ minY: void 0,
+ maxX: void 0,
+ maxY: void 0,
+ width: void 0,
+ height: void 0,
+ startX: void 0,
+ startY: void 0,
+ touchesStart: {},
+ touchesCurrent: {},
+ },
+ v = {
+ x: void 0,
+ y: void 0,
+ prevPositionX: void 0,
+ prevPositionY: void 0,
+ prevTime: void 0,
+ }
+ let w,
+ y = 1
+ function E() {
+ if (m.length < 2) return 1
+ const e = m[0].pageX,
+ t = m[0].pageY,
+ s = m[1].pageX,
+ a = m[1].pageY
+ return Math.sqrt((s - e) ** 2 + (a - t) ** 2)
+ }
+ function S() {
+ const t = e.params.zoom,
+ s = h.imageWrapEl.getAttribute('data-swiper-zoom') || t.maxRatio
+ if (t.limitToOriginalSize && h.imageEl && h.imageEl.naturalWidth) {
+ const e = h.imageEl.naturalWidth / h.imageEl.offsetWidth
+ return Math.min(e, s)
+ }
+ return s
+ }
+ function T(t) {
+ const s = e.isElement ? 'swiper-slide' : `.${e.params.slideClass}`
+ return (
+ !!t.target.matches(s) ||
+ e.slides.filter((e) => e.contains(t.target)).length > 0
+ )
+ }
+ function M(t) {
+ const s = `.${e.params.zoom.containerClass}`
+ return (
+ !!t.target.matches(s) ||
+ [...e.hostEl.querySelectorAll(s)].filter((e) => e.contains(t.target))
+ .length > 0
+ )
+ }
+ function C(t) {
+ if (('mouse' === t.pointerType && m.splice(0, m.length), !T(t))) return
+ const s = e.params.zoom
+ if (((n = !1), (l = !1), m.push(t), !(m.length < 2))) {
+ if (((n = !0), (h.scaleStart = E()), !h.slideEl)) {
+ ;(h.slideEl = t.target.closest(
+ `.${e.params.slideClass}, swiper-slide`
+ )),
+ h.slideEl || (h.slideEl = e.slides[e.activeIndex])
+ let a = h.slideEl.querySelector(`.${s.containerClass}`)
+ if (
+ (a &&
+ (a = a.querySelectorAll(
+ 'picture, img, svg, canvas, .swiper-zoom-target'
+ )[0]),
+ (h.imageEl = a),
+ (h.imageWrapEl = a
+ ? x(h.imageEl, `.${s.containerClass}`)[0]
+ : void 0),
+ !h.imageWrapEl)
+ )
+ return void (h.imageEl = void 0)
+ h.maxRatio = S()
+ }
+ if (h.imageEl) {
+ const [e, t] = (function () {
+ if (m.length < 2) return { x: null, y: null }
+ const e = h.imageEl.getBoundingClientRect()
+ return [
+ (m[0].pageX + (m[1].pageX - m[0].pageX) / 2 - e.x - i.scrollX) /
+ o,
+ (m[0].pageY + (m[1].pageY - m[0].pageY) / 2 - e.y - i.scrollY) /
+ o,
+ ]
+ })()
+ ;(h.originX = e),
+ (h.originY = t),
+ (h.imageEl.style.transitionDuration = '0ms')
+ }
+ c = !0
+ }
+ }
+ function P(t) {
+ if (!T(t)) return
+ const s = e.params.zoom,
+ a = e.zoom,
+ i = m.findIndex((e) => e.pointerId === t.pointerId)
+ i >= 0 && (m[i] = t),
+ m.length < 2 ||
+ ((l = !0),
+ (h.scaleMove = E()),
+ h.imageEl &&
+ ((a.scale = (h.scaleMove / h.scaleStart) * o),
+ a.scale > h.maxRatio &&
+ (a.scale = h.maxRatio - 1 + (a.scale - h.maxRatio + 1) ** 0.5),
+ a.scale < s.minRatio &&
+ (a.scale = s.minRatio + 1 - (s.minRatio - a.scale + 1) ** 0.5),
+ (h.imageEl.style.transform = `translate3d(0,0,0) scale(${a.scale})`)))
+ }
+ function L(t) {
+ if (!T(t)) return
+ if ('mouse' === t.pointerType && 'pointerout' === t.type) return
+ const s = e.params.zoom,
+ a = e.zoom,
+ i = m.findIndex((e) => e.pointerId === t.pointerId)
+ i >= 0 && m.splice(i, 1),
+ n &&
+ l &&
+ ((n = !1),
+ (l = !1),
+ h.imageEl &&
+ ((a.scale = Math.max(Math.min(a.scale, h.maxRatio), s.minRatio)),
+ (h.imageEl.style.transitionDuration = `${e.params.speed}ms`),
+ (h.imageEl.style.transform = `translate3d(0,0,0) scale(${a.scale})`),
+ (o = a.scale),
+ (c = !1),
+ a.scale > 1 && h.slideEl
+ ? h.slideEl.classList.add(`${s.zoomedSlideClass}`)
+ : a.scale <= 1 &&
+ h.slideEl &&
+ h.slideEl.classList.remove(`${s.zoomedSlideClass}`),
+ 1 === a.scale &&
+ ((h.originX = 0), (h.originY = 0), (h.slideEl = void 0))))
+ }
+ function I() {
+ e.touchEventsData.preventTouchMoveFromPointerMove = !1
+ }
+ function z(t) {
+ const s = 'mouse' === t.pointerType && e.params.zoom.panOnMouseMove
+ if (!T(t) || !M(t)) return
+ const a = e.zoom
+ if (!h.imageEl) return
+ if (!f.isTouched || !h.slideEl) return void (s && $(t))
+ if (s) return void $(t)
+ f.isMoved ||
+ ((f.width = h.imageEl.offsetWidth || h.imageEl.clientWidth),
+ (f.height = h.imageEl.offsetHeight || h.imageEl.clientHeight),
+ (f.startX = d(h.imageWrapEl, 'x') || 0),
+ (f.startY = d(h.imageWrapEl, 'y') || 0),
+ (h.slideWidth = h.slideEl.offsetWidth),
+ (h.slideHeight = h.slideEl.offsetHeight),
+ (h.imageWrapEl.style.transitionDuration = '0ms'))
+ const i = f.width * a.scale,
+ r = f.height * a.scale
+ ;(f.minX = Math.min(h.slideWidth / 2 - i / 2, 0)),
+ (f.maxX = -f.minX),
+ (f.minY = Math.min(h.slideHeight / 2 - r / 2, 0)),
+ (f.maxY = -f.minY),
+ (f.touchesCurrent.x = m.length > 0 ? m[0].pageX : t.pageX),
+ (f.touchesCurrent.y = m.length > 0 ? m[0].pageY : t.pageY)
+ if (
+ (Math.max(
+ Math.abs(f.touchesCurrent.x - f.touchesStart.x),
+ Math.abs(f.touchesCurrent.y - f.touchesStart.y)
+ ) > 5 && (e.allowClick = !1),
+ !f.isMoved && !c)
+ ) {
+ if (
+ e.isHorizontal() &&
+ ((Math.floor(f.minX) === Math.floor(f.startX) &&
+ f.touchesCurrent.x < f.touchesStart.x) ||
+ (Math.floor(f.maxX) === Math.floor(f.startX) &&
+ f.touchesCurrent.x > f.touchesStart.x))
+ )
+ return (f.isTouched = !1), void I()
+ if (
+ !e.isHorizontal() &&
+ ((Math.floor(f.minY) === Math.floor(f.startY) &&
+ f.touchesCurrent.y < f.touchesStart.y) ||
+ (Math.floor(f.maxY) === Math.floor(f.startY) &&
+ f.touchesCurrent.y > f.touchesStart.y))
+ )
+ return (f.isTouched = !1), void I()
+ }
+ t.cancelable && t.preventDefault(),
+ t.stopPropagation(),
+ clearTimeout(w),
+ (e.touchEventsData.preventTouchMoveFromPointerMove = !0),
+ (w = setTimeout(() => {
+ e.destroyed || I()
+ })),
+ (f.isMoved = !0)
+ const n = (a.scale - o) / (h.maxRatio - e.params.zoom.minRatio),
+ { originX: l, originY: p } = h
+ ;(f.currentX =
+ f.touchesCurrent.x -
+ f.touchesStart.x +
+ f.startX +
+ n * (f.width - 2 * l)),
+ (f.currentY =
+ f.touchesCurrent.y -
+ f.touchesStart.y +
+ f.startY +
+ n * (f.height - 2 * p)),
+ f.currentX < f.minX &&
+ (f.currentX = f.minX + 1 - (f.minX - f.currentX + 1) ** 0.8),
+ f.currentX > f.maxX &&
+ (f.currentX = f.maxX - 1 + (f.currentX - f.maxX + 1) ** 0.8),
+ f.currentY < f.minY &&
+ (f.currentY = f.minY + 1 - (f.minY - f.currentY + 1) ** 0.8),
+ f.currentY > f.maxY &&
+ (f.currentY = f.maxY - 1 + (f.currentY - f.maxY + 1) ** 0.8),
+ v.prevPositionX || (v.prevPositionX = f.touchesCurrent.x),
+ v.prevPositionY || (v.prevPositionY = f.touchesCurrent.y),
+ v.prevTime || (v.prevTime = Date.now()),
+ (v.x =
+ (f.touchesCurrent.x - v.prevPositionX) /
+ (Date.now() - v.prevTime) /
+ 2),
+ (v.y =
+ (f.touchesCurrent.y - v.prevPositionY) /
+ (Date.now() - v.prevTime) /
+ 2),
+ Math.abs(f.touchesCurrent.x - v.prevPositionX) < 2 && (v.x = 0),
+ Math.abs(f.touchesCurrent.y - v.prevPositionY) < 2 && (v.y = 0),
+ (v.prevPositionX = f.touchesCurrent.x),
+ (v.prevPositionY = f.touchesCurrent.y),
+ (v.prevTime = Date.now()),
+ (h.imageWrapEl.style.transform = `translate3d(${f.currentX}px, ${f.currentY}px,0)`)
+ }
+ function A() {
+ const t = e.zoom
+ h.slideEl &&
+ e.activeIndex !== e.slides.indexOf(h.slideEl) &&
+ (h.imageEl &&
+ (h.imageEl.style.transform = 'translate3d(0,0,0) scale(1)'),
+ h.imageWrapEl &&
+ (h.imageWrapEl.style.transform = 'translate3d(0,0,0)'),
+ h.slideEl.classList.remove(`${e.params.zoom.zoomedSlideClass}`),
+ (t.scale = 1),
+ (o = 1),
+ (h.slideEl = void 0),
+ (h.imageEl = void 0),
+ (h.imageWrapEl = void 0),
+ (h.originX = 0),
+ (h.originY = 0))
+ }
+ function $(e) {
+ if (o <= 1 || !h.imageWrapEl) return
+ if (!T(e) || !M(e)) return
+ const t = i.getComputedStyle(h.imageWrapEl).transform,
+ s = new i.DOMMatrix(t)
+ if (!p)
+ return (
+ (p = !0),
+ (u.x = e.clientX),
+ (u.y = e.clientY),
+ (f.startX = s.e),
+ (f.startY = s.f),
+ (f.width = h.imageEl.offsetWidth || h.imageEl.clientWidth),
+ (f.height = h.imageEl.offsetHeight || h.imageEl.clientHeight),
+ (h.slideWidth = h.slideEl.offsetWidth),
+ void (h.slideHeight = h.slideEl.offsetHeight)
+ )
+ const a = -3 * (e.clientX - u.x),
+ r = -3 * (e.clientY - u.y),
+ n = f.width * o,
+ l = f.height * o,
+ d = h.slideWidth,
+ c = h.slideHeight,
+ m = Math.min(d / 2 - n / 2, 0),
+ g = -m,
+ v = Math.min(c / 2 - l / 2, 0),
+ w = -v,
+ b = Math.max(Math.min(f.startX + a, g), m),
+ y = Math.max(Math.min(f.startY + r, w), v)
+ ;(h.imageWrapEl.style.transitionDuration = '0ms'),
+ (h.imageWrapEl.style.transform = `translate3d(${b}px, ${y}px, 0)`),
+ (u.x = e.clientX),
+ (u.y = e.clientY),
+ (f.startX = b),
+ (f.startY = y),
+ (f.currentX = b),
+ (f.currentY = y)
+ }
+ function k(t) {
+ const s = e.zoom,
+ a = e.params.zoom
+ if (!h.slideEl) {
+ t &&
+ t.target &&
+ (h.slideEl = t.target.closest(
+ `.${e.params.slideClass}, swiper-slide`
+ )),
+ h.slideEl ||
+ (e.params.virtual && e.params.virtual.enabled && e.virtual
+ ? (h.slideEl = g(
+ e.slidesEl,
+ `.${e.params.slideActiveClass}`
+ )[0])
+ : (h.slideEl = e.slides[e.activeIndex]))
+ let s = h.slideEl.querySelector(`.${a.containerClass}`)
+ s &&
+ (s = s.querySelectorAll(
+ 'picture, img, svg, canvas, .swiper-zoom-target'
+ )[0]),
+ (h.imageEl = s),
+ (h.imageWrapEl = s
+ ? x(h.imageEl, `.${a.containerClass}`)[0]
+ : void 0)
+ }
+ if (!h.imageEl || !h.imageWrapEl) return
+ let r, n, l, d, c, p, u, m, v, w, y, E, T, M, C, P, L, I
+ e.params.cssMode &&
+ ((e.wrapperEl.style.overflow = 'hidden'),
+ (e.wrapperEl.style.touchAction = 'none')),
+ h.slideEl.classList.add(`${a.zoomedSlideClass}`),
+ void 0 === f.touchesStart.x && t
+ ? ((r = t.pageX), (n = t.pageY))
+ : ((r = f.touchesStart.x), (n = f.touchesStart.y))
+ const z = o,
+ A = 'number' == typeof t ? t : null
+ 1 === o &&
+ A &&
+ ((r = void 0),
+ (n = void 0),
+ (f.touchesStart.x = void 0),
+ (f.touchesStart.y = void 0))
+ const $ = S()
+ ;(s.scale = A || $),
+ (o = A || $),
+ !t || (1 === o && A)
+ ? ((u = 0), (m = 0))
+ : ((L = h.slideEl.offsetWidth),
+ (I = h.slideEl.offsetHeight),
+ (l = b(h.slideEl).left + i.scrollX),
+ (d = b(h.slideEl).top + i.scrollY),
+ (c = l + L / 2 - r),
+ (p = d + I / 2 - n),
+ (v = h.imageEl.offsetWidth || h.imageEl.clientWidth),
+ (w = h.imageEl.offsetHeight || h.imageEl.clientHeight),
+ (y = v * s.scale),
+ (E = w * s.scale),
+ (T = Math.min(L / 2 - y / 2, 0)),
+ (M = Math.min(I / 2 - E / 2, 0)),
+ (C = -T),
+ (P = -M),
+ z > 0 &&
+ A &&
+ 'number' == typeof f.currentX &&
+ 'number' == typeof f.currentY
+ ? ((u = (f.currentX * s.scale) / z),
+ (m = (f.currentY * s.scale) / z))
+ : ((u = c * s.scale), (m = p * s.scale)),
+ u < T && (u = T),
+ u > C && (u = C),
+ m < M && (m = M),
+ m > P && (m = P)),
+ A && 1 === s.scale && ((h.originX = 0), (h.originY = 0)),
+ (f.currentX = u),
+ (f.currentY = m),
+ (h.imageWrapEl.style.transitionDuration = '300ms'),
+ (h.imageWrapEl.style.transform = `translate3d(${u}px, ${m}px,0)`),
+ (h.imageEl.style.transitionDuration = '300ms'),
+ (h.imageEl.style.transform = `translate3d(0,0,0) scale(${s.scale})`)
+ }
+ function O() {
+ const t = e.zoom,
+ s = e.params.zoom
+ if (!h.slideEl) {
+ e.params.virtual && e.params.virtual.enabled && e.virtual
+ ? (h.slideEl = g(e.slidesEl, `.${e.params.slideActiveClass}`)[0])
+ : (h.slideEl = e.slides[e.activeIndex])
+ let t = h.slideEl.querySelector(`.${s.containerClass}`)
+ t &&
+ (t = t.querySelectorAll(
+ 'picture, img, svg, canvas, .swiper-zoom-target'
+ )[0]),
+ (h.imageEl = t),
+ (h.imageWrapEl = t
+ ? x(h.imageEl, `.${s.containerClass}`)[0]
+ : void 0)
+ }
+ h.imageEl &&
+ h.imageWrapEl &&
+ (e.params.cssMode &&
+ ((e.wrapperEl.style.overflow = ''),
+ (e.wrapperEl.style.touchAction = '')),
+ (t.scale = 1),
+ (o = 1),
+ (f.currentX = void 0),
+ (f.currentY = void 0),
+ (f.touchesStart.x = void 0),
+ (f.touchesStart.y = void 0),
+ (h.imageWrapEl.style.transitionDuration = '300ms'),
+ (h.imageWrapEl.style.transform = 'translate3d(0,0,0)'),
+ (h.imageEl.style.transitionDuration = '300ms'),
+ (h.imageEl.style.transform = 'translate3d(0,0,0) scale(1)'),
+ h.slideEl.classList.remove(`${s.zoomedSlideClass}`),
+ (h.slideEl = void 0),
+ (h.originX = 0),
+ (h.originY = 0),
+ e.params.zoom.panOnMouseMove &&
+ ((u = { x: 0, y: 0 }),
+ p && ((p = !1), (f.startX = 0), (f.startY = 0))))
+ }
+ function D(t) {
+ const s = e.zoom
+ s.scale && 1 !== s.scale ? O() : k(t)
+ }
+ function G() {
+ return {
+ passiveListener: !!e.params.passiveListeners && {
+ passive: !0,
+ capture: !1,
+ },
+ activeListenerWithCapture: !e.params.passiveListeners || {
+ passive: !1,
+ capture: !0,
+ },
+ }
+ }
+ function X() {
+ const t = e.zoom
+ if (t.enabled) return
+ t.enabled = !0
+ const { passiveListener: s, activeListenerWithCapture: a } = G()
+ e.wrapperEl.addEventListener('pointerdown', C, s),
+ e.wrapperEl.addEventListener('pointermove', P, a),
+ ['pointerup', 'pointercancel', 'pointerout'].forEach((t) => {
+ e.wrapperEl.addEventListener(t, L, s)
+ }),
+ e.wrapperEl.addEventListener('pointermove', z, a)
+ }
+ function B() {
+ const t = e.zoom
+ if (!t.enabled) return
+ t.enabled = !1
+ const { passiveListener: s, activeListenerWithCapture: a } = G()
+ e.wrapperEl.removeEventListener('pointerdown', C, s),
+ e.wrapperEl.removeEventListener('pointermove', P, a),
+ ['pointerup', 'pointercancel', 'pointerout'].forEach((t) => {
+ e.wrapperEl.removeEventListener(t, L, s)
+ }),
+ e.wrapperEl.removeEventListener('pointermove', z, a)
+ }
+ Object.defineProperty(e.zoom, 'scale', {
+ get: () => y,
+ set(e) {
+ if (y !== e) {
+ const t = h.imageEl,
+ s = h.slideEl
+ a('zoomChange', e, t, s)
+ }
+ y = e
+ },
+ }),
+ s('init', () => {
+ e.params.zoom.enabled && X()
+ }),
+ s('destroy', () => {
+ B()
+ }),
+ s('touchStart', (t, s) => {
+ e.zoom.enabled &&
+ (function (t) {
+ const s = e.device
+ if (!h.imageEl) return
+ if (f.isTouched) return
+ s.android && t.cancelable && t.preventDefault(),
+ (f.isTouched = !0)
+ const a = m.length > 0 ? m[0] : t
+ ;(f.touchesStart.x = a.pageX), (f.touchesStart.y = a.pageY)
+ })(s)
+ }),
+ s('touchEnd', (t, s) => {
+ e.zoom.enabled &&
+ (function () {
+ const t = e.zoom
+ if (((m.length = 0), !h.imageEl)) return
+ if (!f.isTouched || !f.isMoved)
+ return (f.isTouched = !1), void (f.isMoved = !1)
+ ;(f.isTouched = !1), (f.isMoved = !1)
+ let s = 300,
+ a = 300
+ const i = v.x * s,
+ r = f.currentX + i,
+ n = v.y * a,
+ l = f.currentY + n
+ 0 !== v.x && (s = Math.abs((r - f.currentX) / v.x)),
+ 0 !== v.y && (a = Math.abs((l - f.currentY) / v.y))
+ const o = Math.max(s, a)
+ ;(f.currentX = r), (f.currentY = l)
+ const d = f.width * t.scale,
+ c = f.height * t.scale
+ ;(f.minX = Math.min(h.slideWidth / 2 - d / 2, 0)),
+ (f.maxX = -f.minX),
+ (f.minY = Math.min(h.slideHeight / 2 - c / 2, 0)),
+ (f.maxY = -f.minY),
+ (f.currentX = Math.max(Math.min(f.currentX, f.maxX), f.minX)),
+ (f.currentY = Math.max(Math.min(f.currentY, f.maxY), f.minY)),
+ (h.imageWrapEl.style.transitionDuration = `${o}ms`),
+ (h.imageWrapEl.style.transform = `translate3d(${f.currentX}px, ${f.currentY}px,0)`)
+ })()
+ }),
+ s('doubleTap', (t, s) => {
+ !e.animating &&
+ e.params.zoom.enabled &&
+ e.zoom.enabled &&
+ e.params.zoom.toggle &&
+ D(s)
+ }),
+ s('transitionEnd', () => {
+ e.zoom.enabled && e.params.zoom.enabled && A()
+ }),
+ s('slideChange', () => {
+ e.zoom.enabled && e.params.zoom.enabled && e.params.cssMode && A()
+ }),
+ Object.assign(e.zoom, {
+ enable: X,
+ disable: B,
+ in: k,
+ out: O,
+ toggle: D,
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ function a(e, t) {
+ const s = (function () {
+ let e, t, s
+ return (a, i) => {
+ for (t = -1, e = a.length; e - t > 1; )
+ (s = (e + t) >> 1), a[s] <= i ? (t = s) : (e = s)
+ return e
+ }
+ })()
+ let a, i
+ return (
+ (this.x = e),
+ (this.y = t),
+ (this.lastIndex = e.length - 1),
+ (this.interpolate = function (e) {
+ return e
+ ? ((i = s(this.x, e)),
+ (a = i - 1),
+ ((e - this.x[a]) * (this.y[i] - this.y[a])) /
+ (this.x[i] - this.x[a]) +
+ this.y[a])
+ : 0
+ }),
+ this
+ )
+ }
+ function i() {
+ e.controller.control &&
+ e.controller.spline &&
+ ((e.controller.spline = void 0), delete e.controller.spline)
+ }
+ t({ controller: { control: void 0, inverse: !1, by: 'slide' } }),
+ (e.controller = { control: void 0 }),
+ s('beforeInit', () => {
+ if (
+ 'undefined' != typeof window &&
+ ('string' == typeof e.params.controller.control ||
+ e.params.controller.control instanceof HTMLElement)
+ ) {
+ return void (
+ 'string' == typeof e.params.controller.control
+ ? [...document.querySelectorAll(e.params.controller.control)]
+ : [e.params.controller.control]
+ ).forEach((t) => {
+ if (
+ (e.controller.control || (e.controller.control = []),
+ t && t.swiper)
+ )
+ e.controller.control.push(t.swiper)
+ else if (t) {
+ const s = `${e.params.eventsPrefix}init`,
+ a = (i) => {
+ e.controller.control.push(i.detail[0]),
+ e.update(),
+ t.removeEventListener(s, a)
+ }
+ t.addEventListener(s, a)
+ }
+ })
+ }
+ e.controller.control = e.params.controller.control
+ }),
+ s('update', () => {
+ i()
+ }),
+ s('resize', () => {
+ i()
+ }),
+ s('observerUpdate', () => {
+ i()
+ }),
+ s('setTranslate', (t, s, a) => {
+ e.controller.control &&
+ !e.controller.control.destroyed &&
+ e.controller.setTranslate(s, a)
+ }),
+ s('setTransition', (t, s, a) => {
+ e.controller.control &&
+ !e.controller.control.destroyed &&
+ e.controller.setTransition(s, a)
+ }),
+ Object.assign(e.controller, {
+ setTranslate: function (t, s) {
+ const i = e.controller.control
+ let r, n
+ const l = e.constructor
+ function o(t) {
+ if (t.destroyed) return
+ const s = e.rtlTranslate ? -e.translate : e.translate
+ 'slide' === e.params.controller.by &&
+ (!(function (t) {
+ e.controller.spline = e.params.loop
+ ? new a(e.slidesGrid, t.slidesGrid)
+ : new a(e.snapGrid, t.snapGrid)
+ })(t),
+ (n = -e.controller.spline.interpolate(-s))),
+ (n && 'container' !== e.params.controller.by) ||
+ ((r =
+ (t.maxTranslate() - t.minTranslate()) /
+ (e.maxTranslate() - e.minTranslate())),
+ (!Number.isNaN(r) && Number.isFinite(r)) || (r = 1),
+ (n = (s - e.minTranslate()) * r + t.minTranslate())),
+ e.params.controller.inverse && (n = t.maxTranslate() - n),
+ t.updateProgress(n),
+ t.setTranslate(n, e),
+ t.updateActiveIndex(),
+ t.updateSlidesClasses()
+ }
+ if (Array.isArray(i))
+ for (let e = 0; e < i.length; e += 1)
+ i[e] !== s && i[e] instanceof l && o(i[e])
+ else i instanceof l && s !== i && o(i)
+ },
+ setTransition: function (t, s) {
+ const a = e.constructor,
+ i = e.controller.control
+ let r
+ function n(s) {
+ s.destroyed ||
+ (s.setTransition(t, e),
+ 0 !== t &&
+ (s.transitionStart(),
+ s.params.autoHeight &&
+ l(() => {
+ s.updateAutoHeight()
+ }),
+ S(s.wrapperEl, () => {
+ i && s.transitionEnd()
+ })))
+ }
+ if (Array.isArray(i))
+ for (r = 0; r < i.length; r += 1)
+ i[r] !== s && i[r] instanceof a && n(i[r])
+ else i instanceof a && s !== i && n(i)
+ },
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ a11y: {
+ enabled: !0,
+ notificationClass: 'swiper-notification',
+ prevSlideMessage: 'Previous slide',
+ nextSlideMessage: 'Next slide',
+ firstSlideMessage: 'This is the first slide',
+ lastSlideMessage: 'This is the last slide',
+ paginationBulletMessage: 'Go to slide {{index}}',
+ slideLabelMessage: '{{index}} / {{slidesLength}}',
+ containerMessage: null,
+ containerRoleDescriptionMessage: null,
+ containerRole: null,
+ itemRoleDescriptionMessage: null,
+ slideRole: 'group',
+ id: null,
+ scrollOnFocus: !0,
+ wrapperLiveRegion: !0,
+ },
+ }),
+ (e.a11y = { clicked: !1 })
+ let i,
+ r,
+ n = null,
+ l = new Date().getTime()
+ function o(e) {
+ const t = n
+ 0 !== t.length && P(t, e)
+ }
+ function d(e) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('tabIndex', '0')
+ })
+ }
+ function c(e) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('tabIndex', '-1')
+ })
+ }
+ function p(e, t) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('role', t)
+ })
+ }
+ function u(e, t) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('aria-roledescription', t)
+ })
+ }
+ function m(e, t) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('aria-label', t)
+ })
+ }
+ function h(e) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('aria-disabled', !0)
+ })
+ }
+ function f(e) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('aria-disabled', !1)
+ })
+ }
+ function g(t) {
+ if (13 !== t.keyCode && 32 !== t.keyCode) return
+ const s = e.params.a11y,
+ a = t.target
+ if (
+ !e.pagination ||
+ !e.pagination.el ||
+ (a !== e.pagination.el && !e.pagination.el.contains(t.target)) ||
+ t.target.matches(de(e.params.pagination.bulletClass))
+ ) {
+ if (e.navigation && e.navigation.prevEl && e.navigation.nextEl) {
+ const t = M(e.navigation.prevEl)
+ M(e.navigation.nextEl).includes(a) &&
+ ((e.isEnd && !e.params.loop) || e.slideNext(),
+ e.isEnd ? o(s.lastSlideMessage) : o(s.nextSlideMessage)),
+ t.includes(a) &&
+ ((e.isBeginning && !e.params.loop) || e.slidePrev(),
+ e.isBeginning ? o(s.firstSlideMessage) : o(s.prevSlideMessage))
+ }
+ e.pagination &&
+ a.matches(de(e.params.pagination.bulletClass)) &&
+ a.click()
+ }
+ }
+ function v() {
+ return (
+ e.pagination && e.pagination.bullets && e.pagination.bullets.length
+ )
+ }
+ function b() {
+ return v() && e.params.pagination.clickable
+ }
+ const y = (e, t, s) => {
+ d(e),
+ 'BUTTON' !== e.tagName &&
+ (p(e, 'button'), e.addEventListener('keydown', g)),
+ m(e, s),
+ (function (e, t) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('aria-controls', t)
+ })
+ })(e, t)
+ },
+ x = (t) => {
+ r && r !== t.target && !r.contains(t.target) && (i = !0),
+ (e.a11y.clicked = !0)
+ },
+ S = () => {
+ ;(i = !1),
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ e.destroyed || (e.a11y.clicked = !1)
+ })
+ })
+ },
+ T = (e) => {
+ l = new Date().getTime()
+ },
+ C = (t) => {
+ if (e.a11y.clicked || !e.params.a11y.scrollOnFocus) return
+ if (new Date().getTime() - l < 100) return
+ const s = t.target.closest(`.${e.params.slideClass}, swiper-slide`)
+ if (!s || !e.slides.includes(s)) return
+ r = s
+ const a = e.slides.indexOf(s) === e.activeIndex,
+ n =
+ e.params.watchSlidesProgress &&
+ e.visibleSlides &&
+ e.visibleSlides.includes(s)
+ a ||
+ n ||
+ (t.sourceCapabilities && t.sourceCapabilities.firesTouchEvents) ||
+ (e.isHorizontal() ? (e.el.scrollLeft = 0) : (e.el.scrollTop = 0),
+ requestAnimationFrame(() => {
+ i ||
+ (e.params.loop
+ ? e.slideToLoop(
+ e.getSlideIndexWhenGrid(
+ parseInt(s.getAttribute('data-swiper-slide-index'))
+ ),
+ 0
+ )
+ : e.slideTo(e.getSlideIndexWhenGrid(e.slides.indexOf(s)), 0),
+ (i = !1))
+ }))
+ },
+ L = () => {
+ const t = e.params.a11y
+ t.itemRoleDescriptionMessage &&
+ u(e.slides, t.itemRoleDescriptionMessage),
+ t.slideRole && p(e.slides, t.slideRole)
+ const s = e.slides.length
+ t.slideLabelMessage &&
+ e.slides.forEach((a, i) => {
+ const r = e.params.loop
+ ? parseInt(a.getAttribute('data-swiper-slide-index'), 10)
+ : i
+ m(
+ a,
+ t.slideLabelMessage
+ .replace(/\{\{index\}\}/, r + 1)
+ .replace(/\{\{slidesLength\}\}/, s)
+ )
+ })
+ },
+ I = () => {
+ const t = e.params.a11y
+ e.el.append(n)
+ const s = e.el
+ t.containerRoleDescriptionMessage &&
+ u(s, t.containerRoleDescriptionMessage),
+ t.containerMessage && m(s, t.containerMessage),
+ t.containerRole && p(s, t.containerRole)
+ const i = e.wrapperEl,
+ r =
+ t.id ||
+ i.getAttribute('id') ||
+ `swiper-wrapper-${(function (e = 16) {
+ return 'x'
+ .repeat(e)
+ .replace(/x/g, () =>
+ Math.round(16 * Math.random()).toString(16)
+ )
+ })(16)}`
+ var l
+ if (
+ ((l = r),
+ M(i).forEach((e) => {
+ e.setAttribute('id', l)
+ }),
+ t.wrapperLiveRegion)
+ ) {
+ !(function (e, t) {
+ ;(e = M(e)).forEach((e) => {
+ e.setAttribute('aria-live', t)
+ })
+ })(
+ i,
+ e.params.autoplay && e.params.autoplay.enabled ? 'off' : 'polite'
+ )
+ }
+ L()
+ let { nextEl: o, prevEl: d } = e.navigation ? e.navigation : {}
+ if (
+ ((o = M(o)),
+ (d = M(d)),
+ o && o.forEach((e) => y(e, r, t.nextSlideMessage)),
+ d && d.forEach((e) => y(e, r, t.prevSlideMessage)),
+ b())
+ ) {
+ M(e.pagination.el).forEach((e) => {
+ e.addEventListener('keydown', g)
+ })
+ }
+ a().addEventListener('visibilitychange', T),
+ e.el.addEventListener('focus', C, !0),
+ e.el.addEventListener('focus', C, !0),
+ e.el.addEventListener('pointerdown', x, !0),
+ e.el.addEventListener('pointerup', S, !0)
+ }
+ s('beforeInit', () => {
+ ;(n = w('span', e.params.a11y.notificationClass)),
+ n.setAttribute('aria-live', 'assertive'),
+ n.setAttribute('aria-atomic', 'true')
+ }),
+ s('afterInit', () => {
+ e.params.a11y.enabled && I()
+ }),
+ s(
+ 'slidesLengthChange snapGridLengthChange slidesGridLengthChange',
+ () => {
+ e.params.a11y.enabled && L()
+ }
+ ),
+ s('fromEdge toEdge afterInit lock unlock', () => {
+ e.params.a11y.enabled &&
+ (function () {
+ if (e.params.loop || e.params.rewind || !e.navigation) return
+ const { nextEl: t, prevEl: s } = e.navigation
+ s && (e.isBeginning ? (h(s), c(s)) : (f(s), d(s))),
+ t && (e.isEnd ? (h(t), c(t)) : (f(t), d(t)))
+ })()
+ }),
+ s('paginationUpdate', () => {
+ e.params.a11y.enabled &&
+ (function () {
+ const t = e.params.a11y
+ v() &&
+ e.pagination.bullets.forEach((s) => {
+ e.params.pagination.clickable &&
+ (d(s),
+ e.params.pagination.renderBullet ||
+ (p(s, 'button'),
+ m(
+ s,
+ t.paginationBulletMessage.replace(
+ /\{\{index\}\}/,
+ E(s) + 1
+ )
+ ))),
+ s.matches(de(e.params.pagination.bulletActiveClass))
+ ? s.setAttribute('aria-current', 'true')
+ : s.removeAttribute('aria-current')
+ })
+ })()
+ }),
+ s('destroy', () => {
+ e.params.a11y.enabled &&
+ (function () {
+ n && n.remove()
+ let { nextEl: t, prevEl: s } = e.navigation ? e.navigation : {}
+ ;(t = M(t)),
+ (s = M(s)),
+ t && t.forEach((e) => e.removeEventListener('keydown', g)),
+ s && s.forEach((e) => e.removeEventListener('keydown', g)),
+ b() &&
+ M(e.pagination.el).forEach((e) => {
+ e.removeEventListener('keydown', g)
+ })
+ a().removeEventListener('visibilitychange', T),
+ e.el &&
+ 'string' != typeof e.el &&
+ (e.el.removeEventListener('focus', C, !0),
+ e.el.removeEventListener('pointerdown', x, !0),
+ e.el.removeEventListener('pointerup', S, !0))
+ })()
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ history: {
+ enabled: !1,
+ root: '',
+ replaceState: !1,
+ key: 'slides',
+ keepQuery: !1,
+ },
+ })
+ let a = !1,
+ i = {}
+ const n = (e) =>
+ e
+ .toString()
+ .replace(/\s+/g, '-')
+ .replace(/[^\w-]+/g, '')
+ .replace(/--+/g, '-')
+ .replace(/^-+/, '')
+ .replace(/-+$/, ''),
+ l = (e) => {
+ const t = r()
+ let s
+ s = e ? new URL(e) : t.location
+ const a = s.pathname
+ .slice(1)
+ .split('/')
+ .filter((e) => '' !== e),
+ i = a.length
+ return { key: a[i - 2], value: a[i - 1] }
+ },
+ o = (t, s) => {
+ const i = r()
+ if (!a || !e.params.history.enabled) return
+ let l
+ l = e.params.url ? new URL(e.params.url) : i.location
+ const o =
+ e.virtual && e.params.virtual.enabled
+ ? e.slidesEl.querySelector(`[data-swiper-slide-index="${s}"]`)
+ : e.slides[s]
+ let d = n(o.getAttribute('data-history'))
+ if (e.params.history.root.length > 0) {
+ let s = e.params.history.root
+ '/' === s[s.length - 1] && (s = s.slice(0, s.length - 1)),
+ (d = `${s}/${t ? `${t}/` : ''}${d}`)
+ } else l.pathname.includes(t) || (d = `${t ? `${t}/` : ''}${d}`)
+ e.params.history.keepQuery && (d += l.search)
+ const c = i.history.state
+ ;(c && c.value === d) ||
+ (e.params.history.replaceState
+ ? i.history.replaceState({ value: d }, null, d)
+ : i.history.pushState({ value: d }, null, d))
+ },
+ d = (t, s, a) => {
+ if (s)
+ for (let i = 0, r = e.slides.length; i < r; i += 1) {
+ const r = e.slides[i]
+ if (n(r.getAttribute('data-history')) === s) {
+ const s = e.getSlideIndex(r)
+ e.slideTo(s, t, a)
+ }
+ }
+ else e.slideTo(0, t, a)
+ },
+ c = () => {
+ ;(i = l(e.params.url)), d(e.params.speed, i.value, !1)
+ }
+ s('init', () => {
+ e.params.history.enabled &&
+ (() => {
+ const t = r()
+ if (e.params.history) {
+ if (!t.history || !t.history.pushState)
+ return (
+ (e.params.history.enabled = !1),
+ void (e.params.hashNavigation.enabled = !0)
+ )
+ ;(a = !0),
+ (i = l(e.params.url)),
+ i.key || i.value
+ ? (d(0, i.value, e.params.runCallbacksOnInit),
+ e.params.history.replaceState ||
+ t.addEventListener('popstate', c))
+ : e.params.history.replaceState ||
+ t.addEventListener('popstate', c)
+ }
+ })()
+ }),
+ s('destroy', () => {
+ e.params.history.enabled &&
+ (() => {
+ const t = r()
+ e.params.history.replaceState ||
+ t.removeEventListener('popstate', c)
+ })()
+ }),
+ s('transitionEnd _freeModeNoMomentumRelease', () => {
+ a && o(e.params.history.key, e.activeIndex)
+ }),
+ s('slideChange', () => {
+ a && e.params.cssMode && o(e.params.history.key, e.activeIndex)
+ })
+ },
+ function ({ swiper: e, extendParams: t, emit: s, on: i }) {
+ let n = !1
+ const l = a(),
+ o = r()
+ t({
+ hashNavigation: {
+ enabled: !1,
+ replaceState: !1,
+ watchState: !1,
+ getSlideIndex(t, s) {
+ if (e.virtual && e.params.virtual.enabled) {
+ const t = e.slides.find((e) => e.getAttribute('data-hash') === s)
+ if (!t) return 0
+ return parseInt(t.getAttribute('data-swiper-slide-index'), 10)
+ }
+ return e.getSlideIndex(
+ g(
+ e.slidesEl,
+ `.${e.params.slideClass}[data-hash="${s}"], swiper-slide[data-hash="${s}"]`
+ )[0]
+ )
+ },
+ },
+ })
+ const d = () => {
+ s('hashChange')
+ const t = l.location.hash.replace('#', ''),
+ a =
+ e.virtual && e.params.virtual.enabled
+ ? e.slidesEl.querySelector(
+ `[data-swiper-slide-index="${e.activeIndex}"]`
+ )
+ : e.slides[e.activeIndex]
+ if (t !== (a ? a.getAttribute('data-hash') : '')) {
+ const s = e.params.hashNavigation.getSlideIndex(e, t)
+ if (void 0 === s || Number.isNaN(s)) return
+ e.slideTo(s)
+ }
+ },
+ c = () => {
+ if (!n || !e.params.hashNavigation.enabled) return
+ const t =
+ e.virtual && e.params.virtual.enabled
+ ? e.slidesEl.querySelector(
+ `[data-swiper-slide-index="${e.activeIndex}"]`
+ )
+ : e.slides[e.activeIndex],
+ a = t
+ ? t.getAttribute('data-hash') || t.getAttribute('data-history')
+ : ''
+ e.params.hashNavigation.replaceState &&
+ o.history &&
+ o.history.replaceState
+ ? (o.history.replaceState(null, null, `#${a}` || ''), s('hashSet'))
+ : ((l.location.hash = a || ''), s('hashSet'))
+ }
+ i('init', () => {
+ e.params.hashNavigation.enabled &&
+ (() => {
+ if (
+ !e.params.hashNavigation.enabled ||
+ (e.params.history && e.params.history.enabled)
+ )
+ return
+ n = !0
+ const t = l.location.hash.replace('#', '')
+ if (t) {
+ const s = 0,
+ a = e.params.hashNavigation.getSlideIndex(e, t)
+ e.slideTo(a || 0, s, e.params.runCallbacksOnInit, !0)
+ }
+ e.params.hashNavigation.watchState &&
+ o.addEventListener('hashchange', d)
+ })()
+ }),
+ i('destroy', () => {
+ e.params.hashNavigation.enabled &&
+ e.params.hashNavigation.watchState &&
+ o.removeEventListener('hashchange', d)
+ }),
+ i('transitionEnd _freeModeNoMomentumRelease', () => {
+ n && c()
+ }),
+ i('slideChange', () => {
+ n && e.params.cssMode && c()
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s, emit: i, params: r }) {
+ let n, l
+ ;(e.autoplay = { running: !1, paused: !1, timeLeft: 0 }),
+ t({
+ autoplay: {
+ enabled: !1,
+ delay: 3e3,
+ waitForTransition: !0,
+ disableOnInteraction: !1,
+ stopOnLastSlide: !1,
+ reverseDirection: !1,
+ pauseOnMouseEnter: !1,
+ },
+ })
+ let o,
+ d,
+ c,
+ p,
+ u,
+ m,
+ h,
+ f,
+ g = r && r.autoplay ? r.autoplay.delay : 3e3,
+ v = r && r.autoplay ? r.autoplay.delay : 3e3,
+ w = new Date().getTime()
+ function b(t) {
+ e &&
+ !e.destroyed &&
+ e.wrapperEl &&
+ t.target === e.wrapperEl &&
+ (e.wrapperEl.removeEventListener('transitionend', b),
+ f || (t.detail && t.detail.bySwiperTouchMove) || M())
+ }
+ const y = () => {
+ if (e.destroyed || !e.autoplay.running) return
+ e.autoplay.paused ? (d = !0) : d && ((v = o), (d = !1))
+ const t = e.autoplay.paused ? o : w + v - new Date().getTime()
+ ;(e.autoplay.timeLeft = t),
+ i('autoplayTimeLeft', t, t / g),
+ (l = requestAnimationFrame(() => {
+ y()
+ }))
+ },
+ E = (t) => {
+ if (e.destroyed || !e.autoplay.running) return
+ cancelAnimationFrame(l), y()
+ let s = void 0 === t ? e.params.autoplay.delay : t
+ ;(g = e.params.autoplay.delay), (v = e.params.autoplay.delay)
+ const a = (() => {
+ let t
+ if (
+ ((t =
+ e.virtual && e.params.virtual.enabled
+ ? e.slides.find((e) =>
+ e.classList.contains('swiper-slide-active')
+ )
+ : e.slides[e.activeIndex]),
+ !t)
+ )
+ return
+ return parseInt(t.getAttribute('data-swiper-autoplay'), 10)
+ })()
+ !Number.isNaN(a) &&
+ a > 0 &&
+ void 0 === t &&
+ ((s = a), (g = a), (v = a)),
+ (o = s)
+ const r = e.params.speed,
+ d = () => {
+ e &&
+ !e.destroyed &&
+ (e.params.autoplay.reverseDirection
+ ? !e.isBeginning || e.params.loop || e.params.rewind
+ ? (e.slidePrev(r, !0, !0), i('autoplay'))
+ : e.params.autoplay.stopOnLastSlide ||
+ (e.slideTo(e.slides.length - 1, r, !0, !0), i('autoplay'))
+ : !e.isEnd || e.params.loop || e.params.rewind
+ ? (e.slideNext(r, !0, !0), i('autoplay'))
+ : e.params.autoplay.stopOnLastSlide ||
+ (e.slideTo(0, r, !0, !0), i('autoplay')),
+ e.params.cssMode &&
+ ((w = new Date().getTime()),
+ requestAnimationFrame(() => {
+ E()
+ })))
+ }
+ return (
+ s > 0
+ ? (clearTimeout(n),
+ (n = setTimeout(() => {
+ d()
+ }, s)))
+ : requestAnimationFrame(() => {
+ d()
+ }),
+ s
+ )
+ },
+ x = () => {
+ ;(w = new Date().getTime()),
+ (e.autoplay.running = !0),
+ E(),
+ i('autoplayStart')
+ },
+ S = () => {
+ ;(e.autoplay.running = !1),
+ clearTimeout(n),
+ cancelAnimationFrame(l),
+ i('autoplayStop')
+ },
+ T = (t, s) => {
+ if (e.destroyed || !e.autoplay.running) return
+ clearTimeout(n), t || (h = !0)
+ const a = () => {
+ i('autoplayPause'),
+ e.params.autoplay.waitForTransition
+ ? e.wrapperEl.addEventListener('transitionend', b)
+ : M()
+ }
+ if (((e.autoplay.paused = !0), s))
+ return m && (o = e.params.autoplay.delay), (m = !1), void a()
+ const r = o || e.params.autoplay.delay
+ ;(o = r - (new Date().getTime() - w)),
+ (e.isEnd && o < 0 && !e.params.loop) || (o < 0 && (o = 0), a())
+ },
+ M = () => {
+ ;(e.isEnd && o < 0 && !e.params.loop) ||
+ e.destroyed ||
+ !e.autoplay.running ||
+ ((w = new Date().getTime()),
+ h ? ((h = !1), E(o)) : E(),
+ (e.autoplay.paused = !1),
+ i('autoplayResume'))
+ },
+ C = () => {
+ if (e.destroyed || !e.autoplay.running) return
+ const t = a()
+ 'hidden' === t.visibilityState && ((h = !0), T(!0)),
+ 'visible' === t.visibilityState && M()
+ },
+ P = (t) => {
+ 'mouse' === t.pointerType &&
+ ((h = !0), (f = !0), e.animating || e.autoplay.paused || T(!0))
+ },
+ L = (t) => {
+ 'mouse' === t.pointerType && ((f = !1), e.autoplay.paused && M())
+ }
+ s('init', () => {
+ e.params.autoplay.enabled &&
+ (e.params.autoplay.pauseOnMouseEnter &&
+ (e.el.addEventListener('pointerenter', P),
+ e.el.addEventListener('pointerleave', L)),
+ a().addEventListener('visibilitychange', C),
+ x())
+ }),
+ s('destroy', () => {
+ e.el &&
+ 'string' != typeof e.el &&
+ (e.el.removeEventListener('pointerenter', P),
+ e.el.removeEventListener('pointerleave', L)),
+ a().removeEventListener('visibilitychange', C),
+ e.autoplay.running && S()
+ }),
+ s('_freeModeStaticRelease', () => {
+ ;(p || h) && M()
+ }),
+ s('_freeModeNoMomentumRelease', () => {
+ e.params.autoplay.disableOnInteraction ? S() : T(!0, !0)
+ }),
+ s('beforeTransitionStart', (t, s, a) => {
+ !e.destroyed &&
+ e.autoplay.running &&
+ (a || !e.params.autoplay.disableOnInteraction ? T(!0, !0) : S())
+ }),
+ s('sliderFirstMove', () => {
+ !e.destroyed &&
+ e.autoplay.running &&
+ (e.params.autoplay.disableOnInteraction
+ ? S()
+ : ((c = !0),
+ (p = !1),
+ (h = !1),
+ (u = setTimeout(() => {
+ ;(h = !0), (p = !0), T(!0)
+ }, 200))))
+ }),
+ s('touchEnd', () => {
+ if (!e.destroyed && e.autoplay.running && c) {
+ if (
+ (clearTimeout(u),
+ clearTimeout(n),
+ e.params.autoplay.disableOnInteraction)
+ )
+ return (p = !1), void (c = !1)
+ p && e.params.cssMode && M(), (p = !1), (c = !1)
+ }
+ }),
+ s('slideChange', () => {
+ !e.destroyed && e.autoplay.running && (m = !0)
+ }),
+ Object.assign(e.autoplay, { start: x, stop: S, pause: T, resume: M })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ thumbs: {
+ swiper: null,
+ multipleActiveThumbs: !0,
+ autoScrollOffset: 0,
+ slideThumbActiveClass: 'swiper-slide-thumb-active',
+ thumbsContainerClass: 'swiper-thumbs',
+ },
+ })
+ let i = !1,
+ r = !1
+ function n() {
+ const t = e.thumbs.swiper
+ if (!t || t.destroyed) return
+ const s = t.clickedIndex,
+ a = t.clickedSlide
+ if (a && a.classList.contains(e.params.thumbs.slideThumbActiveClass))
+ return
+ if (null == s) return
+ let i
+ ;(i = t.params.loop
+ ? parseInt(t.clickedSlide.getAttribute('data-swiper-slide-index'), 10)
+ : s),
+ e.params.loop ? e.slideToLoop(i) : e.slideTo(i)
+ }
+ function l() {
+ const { thumbs: t } = e.params
+ if (i) return !1
+ i = !0
+ const s = e.constructor
+ if (t.swiper instanceof s) {
+ if (t.swiper.destroyed) return (i = !1), !1
+ ;(e.thumbs.swiper = t.swiper),
+ Object.assign(e.thumbs.swiper.originalParams, {
+ watchSlidesProgress: !0,
+ slideToClickedSlide: !1,
+ }),
+ Object.assign(e.thumbs.swiper.params, {
+ watchSlidesProgress: !0,
+ slideToClickedSlide: !1,
+ }),
+ e.thumbs.swiper.update()
+ } else if (c(t.swiper)) {
+ const a = Object.assign({}, t.swiper)
+ Object.assign(a, {
+ watchSlidesProgress: !0,
+ slideToClickedSlide: !1,
+ }),
+ (e.thumbs.swiper = new s(a)),
+ (r = !0)
+ }
+ return (
+ e.thumbs.swiper.el.classList.add(
+ e.params.thumbs.thumbsContainerClass
+ ),
+ e.thumbs.swiper.on('tap', n),
+ !0
+ )
+ }
+ function o(t) {
+ const s = e.thumbs.swiper
+ if (!s || s.destroyed) return
+ const a =
+ 'auto' === s.params.slidesPerView
+ ? s.slidesPerViewDynamic()
+ : s.params.slidesPerView
+ let i = 1
+ const r = e.params.thumbs.slideThumbActiveClass
+ if (
+ (e.params.slidesPerView > 1 &&
+ !e.params.centeredSlides &&
+ (i = e.params.slidesPerView),
+ e.params.thumbs.multipleActiveThumbs || (i = 1),
+ (i = Math.floor(i)),
+ s.slides.forEach((e) => e.classList.remove(r)),
+ s.params.loop || (s.params.virtual && s.params.virtual.enabled))
+ )
+ for (let t = 0; t < i; t += 1)
+ g(
+ s.slidesEl,
+ `[data-swiper-slide-index="${e.realIndex + t}"]`
+ ).forEach((e) => {
+ e.classList.add(r)
+ })
+ else
+ for (let t = 0; t < i; t += 1)
+ s.slides[e.realIndex + t] &&
+ s.slides[e.realIndex + t].classList.add(r)
+ const n = e.params.thumbs.autoScrollOffset,
+ l = n && !s.params.loop
+ if (e.realIndex !== s.realIndex || l) {
+ const i = s.activeIndex
+ let r, o
+ if (s.params.loop) {
+ const t = s.slides.find(
+ (t) =>
+ t.getAttribute('data-swiper-slide-index') === `${e.realIndex}`
+ )
+ ;(r = s.slides.indexOf(t)),
+ (o = e.activeIndex > e.previousIndex ? 'next' : 'prev')
+ } else (r = e.realIndex), (o = r > e.previousIndex ? 'next' : 'prev')
+ l && (r += 'next' === o ? n : -1 * n),
+ s.visibleSlidesIndexes &&
+ s.visibleSlidesIndexes.indexOf(r) < 0 &&
+ (s.params.centeredSlides
+ ? (r =
+ r > i
+ ? r - Math.floor(a / 2) + 1
+ : r + Math.floor(a / 2) - 1)
+ : r > i && s.params.slidesPerGroup,
+ s.slideTo(r, t ? 0 : void 0))
+ }
+ }
+ ;(e.thumbs = { swiper: null }),
+ s('beforeInit', () => {
+ const { thumbs: t } = e.params
+ if (t && t.swiper)
+ if (
+ 'string' == typeof t.swiper ||
+ t.swiper instanceof HTMLElement
+ ) {
+ const s = a(),
+ i = () => {
+ const a =
+ 'string' == typeof t.swiper
+ ? s.querySelector(t.swiper)
+ : t.swiper
+ if (a && a.swiper) (t.swiper = a.swiper), l(), o(!0)
+ else if (a) {
+ const s = `${e.params.eventsPrefix}init`,
+ i = (r) => {
+ ;(t.swiper = r.detail[0]),
+ a.removeEventListener(s, i),
+ l(),
+ o(!0),
+ t.swiper.update(),
+ e.update()
+ }
+ a.addEventListener(s, i)
+ }
+ return a
+ },
+ r = () => {
+ if (e.destroyed) return
+ i() || requestAnimationFrame(r)
+ }
+ requestAnimationFrame(r)
+ } else l(), o(!0)
+ }),
+ s('slideChange update resize observerUpdate', () => {
+ o()
+ }),
+ s('setTransition', (t, s) => {
+ const a = e.thumbs.swiper
+ a && !a.destroyed && a.setTransition(s)
+ }),
+ s('beforeDestroy', () => {
+ const t = e.thumbs.swiper
+ t && !t.destroyed && r && t.destroy()
+ }),
+ Object.assign(e.thumbs, { init: l, update: o })
+ },
+ function ({ swiper: e, extendParams: t, emit: s, once: a }) {
+ t({
+ freeMode: {
+ enabled: !1,
+ momentum: !0,
+ momentumRatio: 1,
+ momentumBounce: !0,
+ momentumBounceRatio: 1,
+ momentumVelocityRatio: 1,
+ sticky: !1,
+ minimumVelocity: 0.02,
+ },
+ }),
+ Object.assign(e, {
+ freeMode: {
+ onTouchStart: function () {
+ if (e.params.cssMode) return
+ const t = e.getTranslate()
+ e.setTranslate(t),
+ e.setTransition(0),
+ (e.touchEventsData.velocities.length = 0),
+ e.freeMode.onTouchEnd({
+ currentPos: e.rtl ? e.translate : -e.translate,
+ })
+ },
+ onTouchMove: function () {
+ if (e.params.cssMode) return
+ const { touchEventsData: t, touches: s } = e
+ 0 === t.velocities.length &&
+ t.velocities.push({
+ position: s[e.isHorizontal() ? 'startX' : 'startY'],
+ time: t.touchStartTime,
+ }),
+ t.velocities.push({
+ position: s[e.isHorizontal() ? 'currentX' : 'currentY'],
+ time: o(),
+ })
+ },
+ onTouchEnd: function ({ currentPos: t }) {
+ if (e.params.cssMode) return
+ const {
+ params: i,
+ wrapperEl: r,
+ rtlTranslate: n,
+ snapGrid: l,
+ touchEventsData: d,
+ } = e,
+ c = o() - d.touchStartTime
+ if (t < -e.minTranslate()) e.slideTo(e.activeIndex)
+ else if (t > -e.maxTranslate())
+ e.slides.length < l.length
+ ? e.slideTo(l.length - 1)
+ : e.slideTo(e.slides.length - 1)
+ else {
+ if (i.freeMode.momentum) {
+ if (d.velocities.length > 1) {
+ const t = d.velocities.pop(),
+ s = d.velocities.pop(),
+ a = t.position - s.position,
+ r = t.time - s.time
+ ;(e.velocity = a / r),
+ (e.velocity /= 2),
+ Math.abs(e.velocity) < i.freeMode.minimumVelocity &&
+ (e.velocity = 0),
+ (r > 150 || o() - t.time > 300) && (e.velocity = 0)
+ } else e.velocity = 0
+ ;(e.velocity *= i.freeMode.momentumVelocityRatio),
+ (d.velocities.length = 0)
+ let t = 1e3 * i.freeMode.momentumRatio
+ const c = e.velocity * t
+ let p = e.translate + c
+ n && (p = -p)
+ let u,
+ m = !1
+ const h =
+ 20 * Math.abs(e.velocity) * i.freeMode.momentumBounceRatio
+ let f
+ if (p < e.maxTranslate())
+ i.freeMode.momentumBounce
+ ? (p + e.maxTranslate() < -h &&
+ (p = e.maxTranslate() - h),
+ (u = e.maxTranslate()),
+ (m = !0),
+ (d.allowMomentumBounce = !0))
+ : (p = e.maxTranslate()),
+ i.loop && i.centeredSlides && (f = !0)
+ else if (p > e.minTranslate())
+ i.freeMode.momentumBounce
+ ? (p - e.minTranslate() > h && (p = e.minTranslate() + h),
+ (u = e.minTranslate()),
+ (m = !0),
+ (d.allowMomentumBounce = !0))
+ : (p = e.minTranslate()),
+ i.loop && i.centeredSlides && (f = !0)
+ else if (i.freeMode.sticky) {
+ let t
+ for (let e = 0; e < l.length; e += 1)
+ if (l[e] > -p) {
+ t = e
+ break
+ }
+ ;(p =
+ Math.abs(l[t] - p) < Math.abs(l[t - 1] - p) ||
+ 'next' === e.swipeDirection
+ ? l[t]
+ : l[t - 1]),
+ (p = -p)
+ }
+ if (
+ (f &&
+ a('transitionEnd', () => {
+ e.loopFix()
+ }),
+ 0 !== e.velocity)
+ ) {
+ if (
+ ((t = n
+ ? Math.abs((-p - e.translate) / e.velocity)
+ : Math.abs((p - e.translate) / e.velocity)),
+ i.freeMode.sticky)
+ ) {
+ const s = Math.abs((n ? -p : p) - e.translate),
+ a = e.slidesSizesGrid[e.activeIndex]
+ t =
+ s < a
+ ? i.speed
+ : s < 2 * a
+ ? 1.5 * i.speed
+ : 2.5 * i.speed
+ }
+ } else if (i.freeMode.sticky) return void e.slideToClosest()
+ i.freeMode.momentumBounce && m
+ ? (e.updateProgress(u),
+ e.setTransition(t),
+ e.setTranslate(p),
+ e.transitionStart(!0, e.swipeDirection),
+ (e.animating = !0),
+ S(r, () => {
+ e &&
+ !e.destroyed &&
+ d.allowMomentumBounce &&
+ (s('momentumBounce'),
+ e.setTransition(i.speed),
+ setTimeout(() => {
+ e.setTranslate(u),
+ S(r, () => {
+ e && !e.destroyed && e.transitionEnd()
+ })
+ }, 0))
+ }))
+ : e.velocity
+ ? (s('_freeModeNoMomentumRelease'),
+ e.updateProgress(p),
+ e.setTransition(t),
+ e.setTranslate(p),
+ e.transitionStart(!0, e.swipeDirection),
+ e.animating ||
+ ((e.animating = !0),
+ S(r, () => {
+ e && !e.destroyed && e.transitionEnd()
+ })))
+ : e.updateProgress(p),
+ e.updateActiveIndex(),
+ e.updateSlidesClasses()
+ } else {
+ if (i.freeMode.sticky) return void e.slideToClosest()
+ i.freeMode && s('_freeModeNoMomentumRelease')
+ }
+ ;(!i.freeMode.momentum || c >= i.longSwipesMs) &&
+ (s('_freeModeStaticRelease'),
+ e.updateProgress(),
+ e.updateActiveIndex(),
+ e.updateSlidesClasses())
+ }
+ },
+ },
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ let a, i, r, n
+ t({ grid: { rows: 1, fill: 'column' } })
+ const l = () => {
+ let t = e.params.spaceBetween
+ return (
+ 'string' == typeof t && t.indexOf('%') >= 0
+ ? (t = (parseFloat(t.replace('%', '')) / 100) * e.size)
+ : 'string' == typeof t && (t = parseFloat(t)),
+ t
+ )
+ }
+ s('init', () => {
+ n = e.params.grid && e.params.grid.rows > 1
+ }),
+ s('update', () => {
+ const { params: t, el: s } = e,
+ a = t.grid && t.grid.rows > 1
+ n && !a
+ ? (s.classList.remove(
+ `${t.containerModifierClass}grid`,
+ `${t.containerModifierClass}grid-column`
+ ),
+ (r = 1),
+ e.emitContainerClasses())
+ : !n &&
+ a &&
+ (s.classList.add(`${t.containerModifierClass}grid`),
+ 'column' === t.grid.fill &&
+ s.classList.add(`${t.containerModifierClass}grid-column`),
+ e.emitContainerClasses()),
+ (n = a)
+ }),
+ (e.grid = {
+ initSlides: (t) => {
+ const { slidesPerView: s } = e.params,
+ { rows: n, fill: l } = e.params.grid,
+ o =
+ e.virtual && e.params.virtual.enabled
+ ? e.virtual.slides.length
+ : t.length
+ ;(r = Math.floor(o / n)),
+ (a = Math.floor(o / n) === o / n ? o : Math.ceil(o / n) * n),
+ 'auto' !== s && 'row' === l && (a = Math.max(a, s * n)),
+ (i = a / n)
+ },
+ unsetSlides: () => {
+ e.slides &&
+ e.slides.forEach((t) => {
+ t.swiperSlideGridSet &&
+ ((t.style.height = ''),
+ (t.style[e.getDirectionLabel('margin-top')] = ''))
+ })
+ },
+ updateSlide: (t, s, n) => {
+ const { slidesPerGroup: o } = e.params,
+ d = l(),
+ { rows: c, fill: p } = e.params.grid,
+ u =
+ e.virtual && e.params.virtual.enabled
+ ? e.virtual.slides.length
+ : n.length
+ let m, h, f
+ if ('row' === p && o > 1) {
+ const e = Math.floor(t / (o * c)),
+ i = t - c * o * e,
+ r = 0 === e ? o : Math.min(Math.ceil((u - e * c * o) / c), o)
+ ;(f = Math.floor(i / r)),
+ (h = i - f * r + e * o),
+ (m = h + (f * a) / c),
+ (s.style.order = m)
+ } else
+ 'column' === p
+ ? ((h = Math.floor(t / c)),
+ (f = t - h * c),
+ (h > r || (h === r && f === c - 1)) &&
+ ((f += 1), f >= c && ((f = 0), (h += 1))))
+ : ((f = Math.floor(t / i)), (h = t - f * i))
+ ;(s.row = f),
+ (s.column = h),
+ (s.style.height = `calc((100% - ${(c - 1) * d}px) / ${c})`),
+ (s.style[e.getDirectionLabel('margin-top')] =
+ 0 !== f ? d && `${d}px` : ''),
+ (s.swiperSlideGridSet = !0)
+ },
+ updateWrapperSize: (t, s) => {
+ const { centeredSlides: i, roundLengths: r } = e.params,
+ n = l(),
+ { rows: o } = e.params.grid
+ if (
+ ((e.virtualSize = (t + n) * a),
+ (e.virtualSize = Math.ceil(e.virtualSize / o) - n),
+ e.params.cssMode ||
+ (e.wrapperEl.style[e.getDirectionLabel('width')] = `${
+ e.virtualSize + n
+ }px`),
+ i)
+ ) {
+ const t = []
+ for (let a = 0; a < s.length; a += 1) {
+ let i = s[a]
+ r && (i = Math.floor(i)),
+ s[a] < e.virtualSize + s[0] && t.push(i)
+ }
+ s.splice(0, s.length), s.push(...t)
+ }
+ },
+ })
+ },
+ function ({ swiper: e }) {
+ Object.assign(e, {
+ appendSlide: ce.bind(e),
+ prependSlide: pe.bind(e),
+ addSlide: ue.bind(e),
+ removeSlide: me.bind(e),
+ removeAllSlides: he.bind(e),
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({ fadeEffect: { crossFade: !1 } }),
+ fe({
+ effect: 'fade',
+ swiper: e,
+ on: s,
+ setTranslate: () => {
+ const { slides: t } = e
+ e.params.fadeEffect
+ for (let s = 0; s < t.length; s += 1) {
+ const t = e.slides[s]
+ let a = -t.swiperSlideOffset
+ e.params.virtualTranslate || (a -= e.translate)
+ let i = 0
+ e.isHorizontal() || ((i = a), (a = 0))
+ const r = e.params.fadeEffect.crossFade
+ ? Math.max(1 - Math.abs(t.progress), 0)
+ : 1 + Math.min(Math.max(t.progress, -1), 0),
+ n = ge(0, t)
+ ;(n.style.opacity = r),
+ (n.style.transform = `translate3d(${a}px, ${i}px, 0px)`)
+ }
+ },
+ setTransition: (t) => {
+ const s = e.slides.map((e) => f(e))
+ s.forEach((e) => {
+ e.style.transitionDuration = `${t}ms`
+ }),
+ ve({
+ swiper: e,
+ duration: t,
+ transformElements: s,
+ allSlides: !0,
+ })
+ },
+ overwriteParams: () => ({
+ slidesPerView: 1,
+ slidesPerGroup: 1,
+ watchSlidesProgress: !0,
+ spaceBetween: 0,
+ virtualTranslate: !e.params.cssMode,
+ }),
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ cubeEffect: {
+ slideShadows: !0,
+ shadow: !0,
+ shadowOffset: 20,
+ shadowScale: 0.94,
+ },
+ })
+ const a = (e, t, s) => {
+ let a = s
+ ? e.querySelector('.swiper-slide-shadow-left')
+ : e.querySelector('.swiper-slide-shadow-top'),
+ i = s
+ ? e.querySelector('.swiper-slide-shadow-right')
+ : e.querySelector('.swiper-slide-shadow-bottom')
+ a ||
+ ((a = w(
+ 'div',
+ (
+ 'swiper-slide-shadow-cube swiper-slide-shadow-' +
+ (s ? 'left' : 'top')
+ ).split(' ')
+ )),
+ e.append(a)),
+ i ||
+ ((i = w(
+ 'div',
+ (
+ 'swiper-slide-shadow-cube swiper-slide-shadow-' +
+ (s ? 'right' : 'bottom')
+ ).split(' ')
+ )),
+ e.append(i)),
+ a && (a.style.opacity = Math.max(-t, 0)),
+ i && (i.style.opacity = Math.max(t, 0))
+ }
+ fe({
+ effect: 'cube',
+ swiper: e,
+ on: s,
+ setTranslate: () => {
+ const {
+ el: t,
+ wrapperEl: s,
+ slides: i,
+ width: r,
+ height: n,
+ rtlTranslate: l,
+ size: o,
+ browser: d,
+ } = e,
+ c = C(e),
+ p = e.params.cubeEffect,
+ u = e.isHorizontal(),
+ m = e.virtual && e.params.virtual.enabled
+ let h,
+ f = 0
+ p.shadow &&
+ (u
+ ? ((h = e.wrapperEl.querySelector('.swiper-cube-shadow')),
+ h ||
+ ((h = w('div', 'swiper-cube-shadow')), e.wrapperEl.append(h)),
+ (h.style.height = `${r}px`))
+ : ((h = t.querySelector('.swiper-cube-shadow')),
+ h || ((h = w('div', 'swiper-cube-shadow')), t.append(h))))
+ for (let e = 0; e < i.length; e += 1) {
+ const t = i[e]
+ let s = e
+ m && (s = parseInt(t.getAttribute('data-swiper-slide-index'), 10))
+ let r = 90 * s,
+ n = Math.floor(r / 360)
+ l && ((r = -r), (n = Math.floor(-r / 360)))
+ const d = Math.max(Math.min(t.progress, 1), -1)
+ let h = 0,
+ g = 0,
+ v = 0
+ s % 4 == 0
+ ? ((h = 4 * -n * o), (v = 0))
+ : (s - 1) % 4 == 0
+ ? ((h = 0), (v = 4 * -n * o))
+ : (s - 2) % 4 == 0
+ ? ((h = o + 4 * n * o), (v = o))
+ : (s - 3) % 4 == 0 && ((h = -o), (v = 3 * o + 4 * o * n)),
+ l && (h = -h),
+ u || ((g = h), (h = 0))
+ const w = `rotateX(${c(u ? 0 : -r)}deg) rotateY(${c(
+ u ? r : 0
+ )}deg) translate3d(${h}px, ${g}px, ${v}px)`
+ d <= 1 &&
+ d > -1 &&
+ ((f = 90 * s + 90 * d), l && (f = 90 * -s - 90 * d)),
+ (t.style.transform = w),
+ p.slideShadows && a(t, d, u)
+ }
+ if (
+ ((s.style.transformOrigin = `50% 50% -${o / 2}px`),
+ (s.style['-webkit-transform-origin'] = `50% 50% -${o / 2}px`),
+ p.shadow)
+ )
+ if (u)
+ h.style.transform = `translate3d(0px, ${
+ r / 2 + p.shadowOffset
+ }px, ${-r / 2}px) rotateX(89.99deg) rotateZ(0deg) scale(${
+ p.shadowScale
+ })`
+ else {
+ const e = Math.abs(f) - 90 * Math.floor(Math.abs(f) / 90),
+ t =
+ 1.5 -
+ (Math.sin((2 * e * Math.PI) / 360) / 2 +
+ Math.cos((2 * e * Math.PI) / 360) / 2),
+ s = p.shadowScale,
+ a = p.shadowScale / t,
+ i = p.shadowOffset
+ h.style.transform = `scale3d(${s}, 1, ${a}) translate3d(0px, ${
+ n / 2 + i
+ }px, ${-n / 2 / a}px) rotateX(-89.99deg)`
+ }
+ const g =
+ (d.isSafari || d.isWebView) && d.needPerspectiveFix ? -o / 2 : 0
+ ;(s.style.transform = `translate3d(0px,0,${g}px) rotateX(${c(
+ e.isHorizontal() ? 0 : f
+ )}deg) rotateY(${c(e.isHorizontal() ? -f : 0)}deg)`),
+ s.style.setProperty('--swiper-cube-translate-z', `${g}px`)
+ },
+ setTransition: (t) => {
+ const { el: s, slides: a } = e
+ if (
+ (a.forEach((e) => {
+ ;(e.style.transitionDuration = `${t}ms`),
+ e
+ .querySelectorAll(
+ '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
+ )
+ .forEach((e) => {
+ e.style.transitionDuration = `${t}ms`
+ })
+ }),
+ e.params.cubeEffect.shadow && !e.isHorizontal())
+ ) {
+ const e = s.querySelector('.swiper-cube-shadow')
+ e && (e.style.transitionDuration = `${t}ms`)
+ }
+ },
+ recreateShadows: () => {
+ const t = e.isHorizontal()
+ e.slides.forEach((e) => {
+ const s = Math.max(Math.min(e.progress, 1), -1)
+ a(e, s, t)
+ })
+ },
+ getEffectParams: () => e.params.cubeEffect,
+ perspective: () => !0,
+ overwriteParams: () => ({
+ slidesPerView: 1,
+ slidesPerGroup: 1,
+ watchSlidesProgress: !0,
+ resistanceRatio: 0,
+ spaceBetween: 0,
+ centeredSlides: !1,
+ virtualTranslate: !0,
+ }),
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({ flipEffect: { slideShadows: !0, limitRotation: !0 } })
+ const a = (t, s) => {
+ let a = e.isHorizontal()
+ ? t.querySelector('.swiper-slide-shadow-left')
+ : t.querySelector('.swiper-slide-shadow-top'),
+ i = e.isHorizontal()
+ ? t.querySelector('.swiper-slide-shadow-right')
+ : t.querySelector('.swiper-slide-shadow-bottom')
+ a || (a = we('flip', t, e.isHorizontal() ? 'left' : 'top')),
+ i || (i = we('flip', t, e.isHorizontal() ? 'right' : 'bottom')),
+ a && (a.style.opacity = Math.max(-s, 0)),
+ i && (i.style.opacity = Math.max(s, 0))
+ }
+ fe({
+ effect: 'flip',
+ swiper: e,
+ on: s,
+ setTranslate: () => {
+ const { slides: t, rtlTranslate: s } = e,
+ i = e.params.flipEffect,
+ r = C(e)
+ for (let n = 0; n < t.length; n += 1) {
+ const l = t[n]
+ let o = l.progress
+ e.params.flipEffect.limitRotation &&
+ (o = Math.max(Math.min(l.progress, 1), -1))
+ const d = l.swiperSlideOffset
+ let c = -180 * o,
+ p = 0,
+ u = e.params.cssMode ? -d - e.translate : -d,
+ m = 0
+ e.isHorizontal()
+ ? s && (c = -c)
+ : ((m = u), (u = 0), (p = -c), (c = 0)),
+ (l.style.zIndex = -Math.abs(Math.round(o)) + t.length),
+ i.slideShadows && a(l, o)
+ const h = `translate3d(${u}px, ${m}px, 0px) rotateX(${r(
+ p
+ )}deg) rotateY(${r(c)}deg)`
+ ge(0, l).style.transform = h
+ }
+ },
+ setTransition: (t) => {
+ const s = e.slides.map((e) => f(e))
+ s.forEach((e) => {
+ ;(e.style.transitionDuration = `${t}ms`),
+ e
+ .querySelectorAll(
+ '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
+ )
+ .forEach((e) => {
+ e.style.transitionDuration = `${t}ms`
+ })
+ }),
+ ve({ swiper: e, duration: t, transformElements: s })
+ },
+ recreateShadows: () => {
+ e.params.flipEffect,
+ e.slides.forEach((t) => {
+ let s = t.progress
+ e.params.flipEffect.limitRotation &&
+ (s = Math.max(Math.min(t.progress, 1), -1)),
+ a(t, s)
+ })
+ },
+ getEffectParams: () => e.params.flipEffect,
+ perspective: () => !0,
+ overwriteParams: () => ({
+ slidesPerView: 1,
+ slidesPerGroup: 1,
+ watchSlidesProgress: !0,
+ spaceBetween: 0,
+ virtualTranslate: !e.params.cssMode,
+ }),
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ coverflowEffect: {
+ rotate: 50,
+ stretch: 0,
+ depth: 100,
+ scale: 1,
+ modifier: 1,
+ slideShadows: !0,
+ },
+ }),
+ fe({
+ effect: 'coverflow',
+ swiper: e,
+ on: s,
+ setTranslate: () => {
+ const { width: t, height: s, slides: a, slidesSizesGrid: i } = e,
+ r = e.params.coverflowEffect,
+ n = e.isHorizontal(),
+ l = e.translate,
+ o = n ? t / 2 - l : s / 2 - l,
+ d = n ? r.rotate : -r.rotate,
+ c = r.depth,
+ p = C(e)
+ for (let e = 0, t = a.length; e < t; e += 1) {
+ const t = a[e],
+ s = i[e],
+ l = (o - t.swiperSlideOffset - s / 2) / s,
+ u =
+ 'function' == typeof r.modifier
+ ? r.modifier(l)
+ : l * r.modifier
+ let m = n ? d * u : 0,
+ h = n ? 0 : d * u,
+ f = -c * Math.abs(u),
+ g = r.stretch
+ 'string' == typeof g &&
+ -1 !== g.indexOf('%') &&
+ (g = (parseFloat(r.stretch) / 100) * s)
+ let v = n ? 0 : g * u,
+ w = n ? g * u : 0,
+ b = 1 - (1 - r.scale) * Math.abs(u)
+ Math.abs(w) < 0.001 && (w = 0),
+ Math.abs(v) < 0.001 && (v = 0),
+ Math.abs(f) < 0.001 && (f = 0),
+ Math.abs(m) < 0.001 && (m = 0),
+ Math.abs(h) < 0.001 && (h = 0),
+ Math.abs(b) < 0.001 && (b = 0)
+ const y = `translate3d(${w}px,${v}px,${f}px) rotateX(${p(
+ h
+ )}deg) rotateY(${p(m)}deg) scale(${b})`
+ if (
+ ((ge(0, t).style.transform = y),
+ (t.style.zIndex = 1 - Math.abs(Math.round(u))),
+ r.slideShadows)
+ ) {
+ let e = n
+ ? t.querySelector('.swiper-slide-shadow-left')
+ : t.querySelector('.swiper-slide-shadow-top'),
+ s = n
+ ? t.querySelector('.swiper-slide-shadow-right')
+ : t.querySelector('.swiper-slide-shadow-bottom')
+ e || (e = we('coverflow', t, n ? 'left' : 'top')),
+ s || (s = we('coverflow', t, n ? 'right' : 'bottom')),
+ e && (e.style.opacity = u > 0 ? u : 0),
+ s && (s.style.opacity = -u > 0 ? -u : 0)
+ }
+ }
+ },
+ setTransition: (t) => {
+ e.slides
+ .map((e) => f(e))
+ .forEach((e) => {
+ ;(e.style.transitionDuration = `${t}ms`),
+ e
+ .querySelectorAll(
+ '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
+ )
+ .forEach((e) => {
+ e.style.transitionDuration = `${t}ms`
+ })
+ })
+ },
+ perspective: () => !0,
+ overwriteParams: () => ({ watchSlidesProgress: !0 }),
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ creativeEffect: {
+ limitProgress: 1,
+ shadowPerProgress: !1,
+ progressMultiplier: 1,
+ perspective: !0,
+ prev: {
+ translate: [0, 0, 0],
+ rotate: [0, 0, 0],
+ opacity: 1,
+ scale: 1,
+ },
+ next: {
+ translate: [0, 0, 0],
+ rotate: [0, 0, 0],
+ opacity: 1,
+ scale: 1,
+ },
+ },
+ })
+ const a = (e) => ('string' == typeof e ? e : `${e}px`)
+ fe({
+ effect: 'creative',
+ swiper: e,
+ on: s,
+ setTranslate: () => {
+ const { slides: t, wrapperEl: s, slidesSizesGrid: i } = e,
+ r = e.params.creativeEffect,
+ { progressMultiplier: n } = r,
+ l = e.params.centeredSlides,
+ o = C(e)
+ if (l) {
+ const t = i[0] / 2 - e.params.slidesOffsetBefore || 0
+ s.style.transform = `translateX(calc(50% - ${t}px))`
+ }
+ for (let s = 0; s < t.length; s += 1) {
+ const i = t[s],
+ d = i.progress,
+ c = Math.min(
+ Math.max(i.progress, -r.limitProgress),
+ r.limitProgress
+ )
+ let p = c
+ l ||
+ (p = Math.min(
+ Math.max(i.originalProgress, -r.limitProgress),
+ r.limitProgress
+ ))
+ const u = i.swiperSlideOffset,
+ m = [e.params.cssMode ? -u - e.translate : -u, 0, 0],
+ h = [0, 0, 0]
+ let f = !1
+ e.isHorizontal() || ((m[1] = m[0]), (m[0] = 0))
+ let g = {
+ translate: [0, 0, 0],
+ rotate: [0, 0, 0],
+ scale: 1,
+ opacity: 1,
+ }
+ c < 0
+ ? ((g = r.next), (f = !0))
+ : c > 0 && ((g = r.prev), (f = !0)),
+ m.forEach((e, t) => {
+ m[t] = `calc(${e}px + (${a(g.translate[t])} * ${Math.abs(
+ c * n
+ )}))`
+ }),
+ h.forEach((e, t) => {
+ let s = g.rotate[t] * Math.abs(c * n)
+ h[t] = s
+ }),
+ (i.style.zIndex = -Math.abs(Math.round(d)) + t.length)
+ const v = m.join(', '),
+ w = `rotateX(${o(h[0])}deg) rotateY(${o(h[1])}deg) rotateZ(${o(
+ h[2]
+ )}deg)`,
+ b =
+ p < 0
+ ? `scale(${1 + (1 - g.scale) * p * n})`
+ : `scale(${1 - (1 - g.scale) * p * n})`,
+ y =
+ p < 0
+ ? 1 + (1 - g.opacity) * p * n
+ : 1 - (1 - g.opacity) * p * n,
+ E = `translate3d(${v}) ${w} ${b}`
+ if ((f && g.shadow) || !f) {
+ let e = i.querySelector('.swiper-slide-shadow')
+ if ((!e && g.shadow && (e = we('creative', i)), e)) {
+ const t = r.shadowPerProgress ? c * (1 / r.limitProgress) : c
+ e.style.opacity = Math.min(Math.max(Math.abs(t), 0), 1)
+ }
+ }
+ const x = ge(0, i)
+ ;(x.style.transform = E),
+ (x.style.opacity = y),
+ g.origin && (x.style.transformOrigin = g.origin)
+ }
+ },
+ setTransition: (t) => {
+ const s = e.slides.map((e) => f(e))
+ s.forEach((e) => {
+ ;(e.style.transitionDuration = `${t}ms`),
+ e.querySelectorAll('.swiper-slide-shadow').forEach((e) => {
+ e.style.transitionDuration = `${t}ms`
+ })
+ }),
+ ve({ swiper: e, duration: t, transformElements: s, allSlides: !0 })
+ },
+ perspective: () => e.params.creativeEffect.perspective,
+ overwriteParams: () => ({
+ watchSlidesProgress: !0,
+ virtualTranslate: !e.params.cssMode,
+ }),
+ })
+ },
+ function ({ swiper: e, extendParams: t, on: s }) {
+ t({
+ cardsEffect: {
+ slideShadows: !0,
+ rotate: !0,
+ perSlideRotate: 2,
+ perSlideOffset: 8,
+ },
+ }),
+ fe({
+ effect: 'cards',
+ swiper: e,
+ on: s,
+ setTranslate: () => {
+ const { slides: t, activeIndex: s, rtlTranslate: a } = e,
+ i = e.params.cardsEffect,
+ { startTranslate: r, isTouched: n } = e.touchEventsData,
+ l = a ? -e.translate : e.translate
+ for (let o = 0; o < t.length; o += 1) {
+ const d = t[o],
+ c = d.progress,
+ p = Math.min(Math.max(c, -4), 4)
+ let u = d.swiperSlideOffset
+ e.params.centeredSlides &&
+ !e.params.cssMode &&
+ (e.wrapperEl.style.transform = `translateX(${e.minTranslate()}px)`),
+ e.params.centeredSlides &&
+ e.params.cssMode &&
+ (u -= t[0].swiperSlideOffset)
+ let m = e.params.cssMode ? -u - e.translate : -u,
+ h = 0
+ const f = -100 * Math.abs(p)
+ let g = 1,
+ v = -i.perSlideRotate * p,
+ w = i.perSlideOffset - 0.75 * Math.abs(p)
+ const b =
+ e.virtual && e.params.virtual.enabled
+ ? e.virtual.from + o
+ : o,
+ y =
+ (b === s || b === s - 1) &&
+ p > 0 &&
+ p < 1 &&
+ (n || e.params.cssMode) &&
+ l < r,
+ E =
+ (b === s || b === s + 1) &&
+ p < 0 &&
+ p > -1 &&
+ (n || e.params.cssMode) &&
+ l > r
+ if (y || E) {
+ const t = (1 - Math.abs((Math.abs(p) - 0.5) / 0.5)) ** 0.5
+ ;(v += -28 * p * t),
+ (g += -0.5 * t),
+ (w += 96 * t),
+ (h =
+ (i.rotate || e.isHorizontal() ? -25 : 0) * t * Math.abs(p) +
+ '%')
+ }
+ if (
+ ((m =
+ p < 0
+ ? `calc(${m}px ${a ? '-' : '+'} (${w * Math.abs(p)}%))`
+ : p > 0
+ ? `calc(${m}px ${a ? '-' : '+'} (-${w * Math.abs(p)}%))`
+ : `${m}px`),
+ !e.isHorizontal())
+ ) {
+ const e = h
+ ;(h = m), (m = e)
+ }
+ const x = p < 0 ? '' + (1 + (1 - g) * p) : '' + (1 - (1 - g) * p),
+ S = `\n translate3d(${m}, ${h}, ${f}px)\n rotateZ(${
+ i.rotate ? (a ? -v : v) : 0
+ }deg)\n scale(${x})\n `
+ if (i.slideShadows) {
+ let e = d.querySelector('.swiper-slide-shadow')
+ e || (e = we('cards', d)),
+ e &&
+ (e.style.opacity = Math.min(
+ Math.max((Math.abs(p) - 0.5) / 0.5, 0),
+ 1
+ ))
+ }
+ d.style.zIndex = -Math.abs(Math.round(c)) + t.length
+ ge(0, d).style.transform = S
+ }
+ },
+ setTransition: (t) => {
+ const s = e.slides.map((e) => f(e))
+ s.forEach((e) => {
+ ;(e.style.transitionDuration = `${t}ms`),
+ e.querySelectorAll('.swiper-slide-shadow').forEach((e) => {
+ e.style.transitionDuration = `${t}ms`
+ })
+ }),
+ ve({ swiper: e, duration: t, transformElements: s })
+ },
+ perspective: () => !0,
+ overwriteParams: () => ({
+ _loopSwapReset: !1,
+ watchSlidesProgress: !0,
+ loopAdditionalSlides: e.params.cardsEffect.rotate ? 3 : 2,
+ centeredSlides: !0,
+ virtualTranslate: !e.params.cssMode,
+ }),
+ })
+ },
+ ]
+ return ne.use(be), ne
+})()
+//# sourceMappingURL=swiper-bundle.min.js.map
diff --git a/modules/pp_carousel/views/templates/hook/pp_carousel.tpl b/modules/pp_carousel/views/templates/hook/pp_carousel.tpl
new file mode 100644
index 0000000..df44277
--- /dev/null
+++ b/modules/pp_carousel/views/templates/hook/pp_carousel.tpl
@@ -0,0 +1,67 @@
+
+