diff --git a/.gitignore b/.gitignore index 32b1ec0..ea71a83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.zip ./build/tawkto **/vendor +.phpcs.cache +node_modules/ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..c27d889 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +lint-staged diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 0000000..74ed76a --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,6 @@ +module.exports = { + '*.php': [ + 'composer run lint:fix', + 'composer run lint' + ] +} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..42e31a0 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20.14.0 diff --git a/.phpcs.xml b/.phpcs.xml new file mode 100644 index 0000000..a0eb3dd --- /dev/null +++ b/.phpcs.xml @@ -0,0 +1,26 @@ + + + Custom coding standards. + + \.github/* + */docker/* + */vendor/* + */node_modules/* + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 932394d..9c854ad 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,36 @@ Free live chat widget for your site ## Description -The tawk.to Live Chat app makes it easy to monitor and chat with visitors on your website. Be there when they need you with unlimited messaging, ticketing and your own Knowledge Base — all 100% FREE. +The tawk.to Live Chat app makes it easy to monitor and chat with visitors on +your website. Be there when they need you with unlimited messaging, ticketing +and your own Knowledge Base — all 100% FREE. -Compatible with all modern browsers, tawk.to was created in response to the growing need for businesses to respond in real time, with real people. +Compatible with all modern browsers, tawk.to was created in response to the +growing need for businesses to respond in real time, with real people. -Never lose another lead or sale again — tawk.to offers iOS, Android, Windows and Mac OSX apps to keep you connected wherever you go. +Never lose another lead or sale again — tawk.to offers iOS, Android, Windows and +Mac OSX apps to keep you connected wherever you go. -Don’t have a tawk.to account yet? [Create one here.](https://www.tawk.to/?utm_source=prestashop&utm_medium=link&utm_campaign=signup) +Don’t have a tawk.to account yet? +[Create one here.](https://www.tawk.to/?utm_source=prestashop&utm_medium=link&utm_campaign=signup) ## Installation ### Prestashop 1.6 -This section describes how to install the plugin and get it working on Prestashop 1.6 +This section describes how to install the plugin and get it working on +Prestashop 1.6 #### Module Installer -1. Download the `tawk-prestashop-1.6-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download the `tawk-prestashop-1.6-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Go to `Dashboard` -> `Modules and Services`. -3. Click `Add a new module`, upload the zip file, and click `Upload this module`. +3. Click `Add a new module`, upload the zip file, and click +`Upload this module`. 4. Search for the `tawk.to` plugin and `install`. #### Manual Installation -1. Download and extract the `tawk-prestashop-1.6-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download and extract the `tawk-prestashop-1.6-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Upload `tawkto` directory to the `/modules/` directory. 3. Go to `Dashboard` -> `Modules and Services`. 4. Search for the `tawk.to` plugin and `install`. @@ -33,15 +42,19 @@ This section describes how to install the plugin and get it working on Prestasho It is under `Dashboard` -> `Administration` -> `tawk.to`. ### Prestashop 1.7 -This section describes how to install the plugin and get it working on Prestashop 1.7 +This section describes how to install the plugin and get it working on +Prestashop 1.7 #### Module Installer -1. Download the `tawk-prestashop-1.7-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download the `tawk-prestashop-1.7-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Go to `Dashboard` -> `Modules` -> `Module Manager`. -3. Click `Upload a module`, upload the zip file, and the module will install automatically. +3. Click `Upload a module`, upload the zip file, and the module will install +automatically. #### Manual Installation -1. Download and extract the `tawk-prestashop-1.7-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download and extract the `tawk-prestashop-1.7-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Upload `tawkto` directory to the `/modules/` directory. 3. Go to `Dashboard` -> `Modules` -> `Module Catalog`. 4. Search for the `tawk.to` plugin and `install`. @@ -52,7 +65,8 @@ It is under `Dashboard` -> `More` -> `tawk.to`. ### Widget Configuration 1. Go to the configuration page. 2. Log in to your tawk.to account. -3. Select the property and the widget you want to place on your store and click `Use selected widget`. +3. Select the property and the widget you want to place on your store and click +`Use selected widget`. 4. The widget will now appear on your store. ## Frequently Asked Questions diff --git a/composer.json b/composer.json index e5bc667..ca24501 100644 --- a/composer.json +++ b/composer.json @@ -13,16 +13,26 @@ }, "license": "AFL-3.0", "scripts": { + "post-install-cmd": "npm install", + "lint": "phpcs -p -s -v --runtime-set ignore_warnings_on_exit true .", + "lint:fix": "phpcbf -p -s -v .; err=$?; if [ $err -eq 1 ]; then exit 0; else exit $err; fi;", "auto-index": "composer run auto-index:1.6 && composer run auto-index:1.7", "auto-index:1.6": "autoindex prestashop:add:index ./prestashop1.6", "auto-index:1.7": "autoindex prestashop:add:index ./prestashop1.7", "build": "composer run build:dev && composer run build:prod", - "build:dev" : "composer install", - "build:prod" : "composer run build:1.6 && composer run build:1.7", - "build:1.6" : "COMPOSER_VENDOR_DIR=./prestashop1.6/vendor composer install --no-dev", - "build:1.7" : "COMPOSER_VENDOR_DIR=./prestashop1.7/vendor composer install --no-dev" + "build:dev": "composer install", + "build:prod": "composer run build:1.6 && composer run build:1.7", + "build:1.6": "COMPOSER_VENDOR_DIR=./prestashop1.6/vendor composer install --no-dev", + "build:1.7": "COMPOSER_VENDOR_DIR=./prestashop1.7/vendor composer install --no-dev" }, "require-dev": { - "prestashop/autoindex": "^2.0" + "prestashop/autoindex": "^2.0", + "squizlabs/php_codesniffer": "^3.10", + "drupal/coder": "^8.3" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/composer.lock b/composer.lock index f46d088..fedf2ab 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b200ad8c6cea27c6f148575eca71159e", + "content-hash": "bf5b273f6a97eaa4d47596a50c369ef7", "packages": [ { "name": "tawk/url-utils", @@ -57,23 +57,152 @@ } ], "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "drupal/coder", + "version": "8.3.24", + "source": { + "type": "git", + "url": "https://github.com/pfrenssen/coder.git", + "reference": "1a59890f972db5da091354f0191dec1037f7c582" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pfrenssen/coder/zipball/1a59890f972db5da091354f0191dec1037f7c582", + "reference": "1a59890f972db5da091354f0191dec1037f7c582", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1 || ^1.0.0", + "ext-mbstring": "*", + "php": ">=7.2", + "sirbrillig/phpcs-variable-analysis": "^2.11.7", + "slevomat/coding-standard": "^8.11", + "squizlabs/php_codesniffer": "^3.9.1", + "symfony/yaml": ">=3.4.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.7.12", + "phpunit/phpunit": "^8.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Drupal\\": "coder_sniffer/Drupal/", + "DrupalPractice\\": "coder_sniffer/DrupalPractice/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "Coder is a library to review Drupal code.", + "homepage": "https://www.drupal.org/project/coder", + "keywords": [ + "code review", + "phpcs", + "standards" + ], + "support": { + "issues": "https://www.drupal.org/project/issues/coder", + "source": "https://www.drupal.org/project/coder" + }, + "time": "2024-04-21T06:13:24+00:00" + }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v4.19.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.1" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", @@ -109,29 +238,76 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2024-03-17T08:10:35+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.29.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" + }, + "time": "2024-05-31T08:52:43+00:00" }, { "name": "prestashop/autoindex", - "version": "v2.0.0", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/PrestaShopCorp/autoindex.git", - "reference": "355c224de4ca8766d63a038dcdcb24f56cb19fec" + "reference": "235f3ec115432ffc32d582198ea498467b3946d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PrestaShopCorp/autoindex/zipball/355c224de4ca8766d63a038dcdcb24f56cb19fec", - "reference": "355c224de4ca8766d63a038dcdcb24f56cb19fec", + "url": "https://api.github.com/repos/PrestaShopCorp/autoindex/zipball/235f3ec115432ffc32d582198ea498467b3946d0", + "reference": "235f3ec115432ffc32d582198ea498467b3946d0", "shasum": "" }, "require": { "nikic/php-parser": "^4.10", - "php": ">=7.2", - "symfony/console": "^3.4 || ~4.0 || ~5.0", - "symfony/finder": "^3.4 || ~4.0 || ~5.0" + "php": "^8.0 || ^7.2", + "symfony/console": "^3.4 || ~4.0 || ~5.0 || ~6.0", + "symfony/finder": "^3.4 || ~4.0 || ~5.0 || ~6.0" }, "require-dev": { "phpstan/phpstan": "^0.12.83", @@ -159,9 +335,9 @@ "description": "Automatically add an 'index.php' in all the current or specified directories and all sub-directories.", "homepage": "https://github.com/PrestaShopCorp/autoindex", "support": { - "source": "https://github.com/PrestaShopCorp/autoindex/tree/v2.0.0" + "source": "https://github.com/PrestaShopCorp/autoindex/tree/v2.1.0" }, - "time": "2021-06-09T15:37:17+00:00" + "time": "2022-10-10T08:35:00+00:00" }, { "name": "psr/container", @@ -216,54 +392,252 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "sirbrillig/phpcs-variable-analysis", + "version": "v2.11.19", + "source": { + "type": "git", + "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", + "reference": "bc8d7e30e2005bce5c59018b7cdb08e9fb45c0d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/bc8d7e30e2005bce5c59018b7cdb08e9fb45c0d1", + "reference": "bc8d7e30e2005bce5c59018b7cdb08e9fb45c0d1", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "squizlabs/php_codesniffer": "^3.5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpcsstandards/phpcsdevcs": "^1.1", + "phpstan/phpstan": "^1.7", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0", + "sirbrillig/phpcs-import-detection": "^1.1", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0@beta" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "VariableAnalysis\\": "VariableAnalysis/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Sam Graham", + "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" + } + ], + "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], + "support": { + "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", + "source": "https://github.com/sirbrillig/phpcs-variable-analysis", + "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" + }, + "time": "2024-06-26T20:08:34+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.15.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "7d1d957421618a3803b593ec31ace470177d7817" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2024-03-09T15:20:58+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.10.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-07-21T23:26:44+00:00" + }, { "name": "symfony/console", - "version": "v5.4.8", + "version": "v6.4.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b" + "reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b", - "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b", + "url": "https://api.github.com/repos/symfony/console/zipball/504974cbe43d05f83b201d6498c206f16fc0cdbc", + "reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -292,12 +666,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.8" + "source": "https://github.com/symfony/console/tree/v6.4.10" }, "funding": [ { @@ -313,29 +687,29 @@ "type": "tidelift" } ], - "time": "2022-04-12T16:02:29+00:00" + "time": "2024-07-26T12:30:32+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.0.1", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", - "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -364,7 +738,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -380,26 +754,27 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/finder", - "version": "v5.4.8", + "version": "v6.4.10", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" + "reference": "af29198d87112bebdd397bd7735fbd115997824c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", + "url": "https://api.github.com/repos/symfony/finder/zipball/af29198d87112bebdd397bd7735fbd115997824c", + "reference": "af29198d87112bebdd397bd7735fbd115997824c", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -427,7 +802,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.8" + "source": "https://github.com/symfony/finder/tree/v6.4.10" }, "funding": [ { @@ -443,20 +818,20 @@ "type": "tidelift" } ], - "time": "2022-04-15T08:07:45+00:00" + "time": "2024-07-24T07:06:38+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", "shasum": "" }, "require": { @@ -470,9 +845,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -509,7 +881,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" }, "funding": [ { @@ -525,20 +897,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", + "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", "shasum": "" }, "require": { @@ -549,9 +921,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -590,7 +959,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" }, "funding": [ { @@ -606,20 +975,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", "shasum": "" }, "require": { @@ -630,9 +999,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -674,7 +1040,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" }, "funding": [ { @@ -690,20 +1056,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", "shasum": "" }, "require": { @@ -717,9 +1083,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -757,7 +1120,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" }, "funding": [ { @@ -773,123 +1136,46 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2024-06-19T12:30:46+00:00" }, { - "name": "symfony/polyfill-php73", - "version": "v1.25.0", + "name": "symfony/service-contracts", + "version": "v3.5.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-06-05T21:20:04+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.25.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "shasum": "" - }, - "require": { - "php": ">=7.1" + "conflict": { + "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "3.5-dev" }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Contracts\\Service\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -897,10 +1183,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -910,16 +1192,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Generic abstractions related to writing services", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -935,46 +1219,51 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { - "name": "symfony/service-contracts", - "version": "v3.0.1", + "name": "symfony/string", + "version": "v7.1.3", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "e517458f278c2131ca9f262f8fbaf01410f2c65c" + "url": "https://github.com/symfony/string.git", + "reference": "ea272a882be7f20cad58d5d78c215001617b7f07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e517458f278c2131ca9f262f8fbaf01410f2c65c", - "reference": "e517458f278c2131ca9f262f8fbaf01410f2c65c", + "url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07", + "reference": "ea272a882be7f20cad58d5d78c215001617b7f07", "shasum": "" }, "require": { - "php": ">=8.0.2", - "psr/container": "^2.0" + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "ext-psr": "<1.1|>=2" + "symfony/translation-contracts": "<2.5" }, - "suggest": { - "symfony/service-implementation": "" + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -990,18 +1279,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.0.1" + "source": "https://github.com/symfony/string/tree/v7.1.3" }, "funding": [ { @@ -1017,45 +1306,39 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:10:05+00:00" + "time": "2024-07-22T10:25:37+00:00" }, { - "name": "symfony/string", - "version": "v6.0.8", + "name": "symfony/yaml", + "version": "v7.1.1", "source": { "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "ac0aa5c2282e0de624c175b68d13f2c8f2e2649d" + "url": "https://github.com/symfony/yaml.git", + "reference": "fa34c77015aa6720469db7003567b9f772492bf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ac0aa5c2282e0de624c175b68d13f2c8f2e2649d", - "reference": "ac0aa5c2282e0de624c175b68d13f2c8f2e2649d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/fa34c77015aa6720469db7003567b9f772492bf2", + "reference": "fa34c77015aa6720469db7003567b9f772492bf2", "shasum": "" }, "require": { - "php": ">=8.0.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.2", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/console": "<6.4" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/translation-contracts": "^2.0|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/console": "^6.4|^7.0" }, + "bin": [ + "Resources/bin/yaml-lint" + ], "type": "library", "autoload": { - "files": [ - "Resources/functions.php" - ], "psr-4": { - "Symfony\\Component\\String\\": "" + "Symfony\\Component\\Yaml\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1067,26 +1350,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], "support": { - "source": "https://github.com/symfony/string/tree/v6.0.8" + "source": "https://github.com/symfony/yaml/tree/v7.1.1" }, "funding": [ { @@ -1102,7 +1377,7 @@ "type": "tidelift" } ], - "time": "2022-04-22T08:18:02+00:00" + "time": "2024-05-31T14:57:53+00:00" } ], "aliases": [], @@ -1112,5 +1387,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.6.0" } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7b2ff64 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,728 @@ +{ + "name": "tawk-prestashop", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tawk-prestashop", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "husky": "^9.1.5", + "lint-staged": "^15.2.9" + } + }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", + "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", + "dev": true, + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", + "integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f83d89e --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "tawk-prestashop", + "version": "1.0.0", + "description": "Free live chat widget for your site", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "prepare": "husky" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/tawk/tawk-prestashop.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/tawk/tawk-prestashop/issues" + }, + "homepage": "https://github.com/tawk/tawk-prestashop#readme", + "devDependencies": { + "husky": "^9.1.5", + "lint-staged": "^15.2.9" + } +} diff --git a/prestashop1.6/README.md b/prestashop1.6/README.md index d9a0e61..66a4dc1 100644 --- a/prestashop1.6/README.md +++ b/prestashop1.6/README.md @@ -4,25 +4,33 @@ Free live chat widget for your site ## Description -The tawk.to Live Chat app makes it easy to monitor and chat with visitors on your website. Be there when they need you with unlimited messaging, ticketing and your own Knowledge Base — all 100% FREE. +The tawk.to Live Chat app makes it easy to monitor and chat with visitors on +your website. Be there when they need you with unlimited messaging, ticketing +and your own Knowledge Base — all 100% FREE. -Compatible with all modern browsers, tawk.to was created in response to the growing need for businesses to respond in real time, with real people. +Compatible with all modern browsers, tawk.to was created in response to the +growing need for businesses to respond in real time, with real people. -Never lose another lead or sale again — tawk.to offers iOS, Android, Windows and Mac OSX apps to keep you connected wherever you go. +Never lose another lead or sale again — tawk.to offers iOS, Android, Windows +and Mac OSX apps to keep you connected wherever you go. -Don’t have a tawk.to account yet? [Create one here.](https://www.tawk.to/?utm_source=prestashop&utm_medium=link&utm_campaign=signup) +Don’t have a tawk.to account yet? +[Create one here.](https://www.tawk.to/?utm_source=prestashop&utm_medium=link&utm_campaign=signup) ## Installation This section describes how to install the plugin and get it working. ### Module Installer -1. Download the `tawk-prestashop-1.6-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download the `tawk-prestashop-1.6-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Go to `Dashboard` -> `Modules and Services`. -3. Click `Add a new module`, upload the zip file, and click `Upload this module`. +3. Click `Add a new module`, upload the zip file, and click +`Upload this module`. 4. Search for the `tawk.to` plugin and `install`. ### Manual Installation -1. Download and extract the `tawk-prestashop-1.6-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download and extract the `tawk-prestashop-1.6-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Upload `tawkto` directory to the `/modules/` directory. 3. Go to `Dashboard` -> `Modules and Services`. 4. Search for the `tawk.to` plugin and `install`. @@ -33,7 +41,8 @@ It is under `Dashboard` -> `Administration` -> `tawk.to`. ### Widget Configuration 1. Go to the configuration page. 2. Log in to your tawk.to account. -3. Select the property and the widget you want to place on your store and click `Use selected widget`. +3. Select the property and the widget you want to place on your store and click +`Use selected widget`. 4. The widget will now appear on your store. ## Frequently Asked Questions diff --git a/prestashop1.6/controllers/admin/AdminTawktoController.php b/prestashop1.6/controllers/admin/AdminTawktoController.php index 06c72d2..87cfa51 100644 --- a/prestashop1.6/controllers/admin/AdminTawktoController.php +++ b/prestashop1.6/controllers/admin/AdminTawktoController.php @@ -1,4 +1,5 @@ bootstrap = true; - $this->display = 'view'; - $this->meta_title = $this->l('tawk.to'); - - parent::__construct(); - if (!$this->module->active) { - Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome')); - } +/** + * Admin settings controller + */ +class AdminTawktoController extends ModuleAdminController { + + /** + * __construct + * + * @return void + */ + public function __construct() { + $this->bootstrap = TRUE; + $this->display = 'view'; + $this->meta_title = $this->l('tawk.to'); + + parent::__construct(); + if (!$this->module->active) { + Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome')); } - - public function initToolBarTitle() - { - $this->toolbar_title[] = $this->l('tawk.to'); - $this->toolbar_title[] = $this->l('Widget'); + } + + /** + * Set toolbar title + * + * @return void + */ + public function initToolBarTitle() { + $this->toolbar_title[] = $this->l('tawk.to'); + $this->toolbar_title[] = $this->l('Widget'); + } + + /** + * Set toolbar actions + * + * @return mixed + */ + public function initToolbar() { + $r = parent::initToolbar(); + + if (isset($this->toolbar_btn)) { + unset($this->toolbar_btn['back']); } - - public function initToolbar() - { - $r = parent::initToolbar(); - - if (isset($this->toolbar_btn)) { - unset($this->toolbar_btn['back']); - } else { - unset($this->page_header_toolbar_btn['back']); - } - - return $r; + else { + unset($this->page_header_toolbar_btn['back']); } - public function renderView() - { - // get current shopId - $shop = Context::getContext()->shop; - $domain = $shop->domain; - - $optKey = TawkTo::TAWKTO_WIDGET_OPTS; - - // returns 'false' if retrieved none. - $displayOpts = Configuration::get($optKey); - if (!$displayOpts) { - $displayOpts = null; - } - $displayOpts = Tools::jsonDecode($displayOpts); - - $sameUser = true; // assuming there is only one admin by default - $empId = Configuration::get(TawkTo::TAWKTO_WIDGET_USER); - if ($this->context->employee->id != $empId && $empId) { - $sameUser = false; - } - - $currentWidget = TawkTo::getPropertyAndWidget(); - $pageId = ''; - $widgetId = ''; - if (!empty($currentWidget)) { - $pageId = $currentWidget['page_id']; - $widgetId = $currentWidget['widget_id']; - } - - $this->tpl_view_vars = array( - 'iframe_url' => $this->getIframeUrl(), - 'base_url' => $this->getBaseUrl(), - 'controller' => $this->context->link->getAdminLink('AdminTawkto'), - 'tab_id' => (int) $this->context->controller->id, - 'domain' => $domain, - 'display_opts' => $displayOpts, - 'page_id' => $pageId, - 'widget_id' => $widgetId, - 'same_user' => $sameUser - ); - - return parent::renderView(); + return $r; + } + + /** + * Render admin widget settings view + * + * @return string + */ + public function renderView() { + // get current shopId + $shop = Context::getContext()->shop; + $domain = $shop->domain; + + $optKey = TawkTo::TAWKTO_WIDGET_OPTS; + + // returns 'false' if retrieved none. + $displayOpts = Configuration::get($optKey); + if (!$displayOpts) { + $displayOpts = NULL; } + $displayOpts = Tools::jsonDecode($displayOpts); - private function getBaseUrl() - { - return 'https://plugins.tawk.to'; + $sameUser = TRUE; // assuming there is only one admin by default + $empId = Configuration::get(TawkTo::TAWKTO_WIDGET_USER); + if ($this->context->employee->id != $empId && $empId) { + $sameUser = FALSE; } - private function getIframeUrl() - { - $currentWidget = TawkTo::getPropertyAndWidget(); - $pageId = ''; - $widgetId = ''; - if (!empty($currentWidget)) { - $pageId = $currentWidget['page_id']; - $widgetId = $currentWidget['widget_id']; - } - - return $this->getBaseUrl() - .'/generic/widgets' - .'?currentPageId='.$pageId - .'¤tWidgetId='.$widgetId; + $currentWidget = TawkTo::getPropertyAndWidget(); + $pageId = ''; + $widgetId = ''; + if (!empty($currentWidget)) { + $pageId = $currentWidget['page_id']; + $widgetId = $currentWidget['widget_id']; } - private static function idsAreCorrect($pageId, $widgetId) - { - return preg_match('/^[0-9A-Fa-f]{24}$/', $pageId) === 1 && preg_match('/^[a-z0-9]{1,50}$/i', $widgetId) === 1; + $this->tpl_view_vars = [ + 'iframe_url' => $this->getIframeUrl(), + 'base_url' => $this->getBaseUrl(), + 'controller' => $this->context->link->getAdminLink('AdminTawkto'), + 'tab_id' => (int) $this->context->controller->id, + 'domain' => $domain, + 'display_opts' => $displayOpts, + 'page_id' => $pageId, + 'widget_id' => $widgetId, + 'same_user' => $sameUser, + ]; + + return parent::renderView(); + } + + /** + * Base plugin URL + * + * @return string + */ + private function getBaseUrl() { + return 'https://plugins.tawk.to'; + } + + /** + * Generates iframe URL + * + * @return string + */ + private function getIframeUrl() { + $currentWidget = TawkTo::getPropertyAndWidget(); + $pageId = ''; + $widgetId = ''; + if (!empty($currentWidget)) { + $pageId = $currentWidget['page_id']; + $widgetId = $currentWidget['widget_id']; } - public function ajaxProcessSetWidget() - { - if (!Tools::getIsset('pageId') || !Tools::getIsset('widgetId')) { - die(Tools::jsonEncode(array('success' => false))); - } - - $pageId = Tools::getValue('pageId'); - $widgetId = Tools::getValue('widgetId'); - if (!self::idsAreCorrect($pageId, $widgetId)) { - die(Tools::jsonEncode(array('success' => false))); - } - - $currentWidgetKey = TawkTo::TAWKTO_SELECTED_WIDGET; - Configuration::updateValue($currentWidgetKey, $pageId.':'.$widgetId); + return $this->getBaseUrl() + . '/generic/widgets?currentPageId=' . $pageId + . '¤tWidgetId=' . $widgetId; + } + + /** + * Validate page ID and widget ID + * + * @param string $pageId Page ID. + * @param string $widgetId Widget ID. + * @return integer|false + */ + private static function idsAreCorrect(string $pageId, string $widgetId) { + return preg_match('/^[0-9A-Fa-f]{24}$/', $pageId) === 1 && preg_match('/^[a-z0-9]{1,50}$/i', $widgetId) === 1; + } + + /** + * Save widget page ID and widget ID + * + * @return void + */ + public function ajaxProcessSetWidget() { + if (!Tools::getIsset('pageId') || !Tools::getIsset('widgetId')) { + die(Tools::jsonEncode(['success' => FALSE])); + } - $userKey = TawkTo::TAWKTO_WIDGET_USER; - Configuration::updateValue($userKey, $this->context->employee->id); + $pageId = Tools::getValue('pageId'); + $widgetId = Tools::getValue('widgetId'); + if (!self::idsAreCorrect($pageId, $widgetId)) { + die(Tools::jsonEncode(['success' => FALSE])); + } - die(Tools::jsonEncode(array('success' => true))); + $currentWidgetKey = TawkTo::TAWKTO_SELECTED_WIDGET; + Configuration::updateValue($currentWidgetKey, $pageId . ':' . $widgetId); + + $userKey = TawkTo::TAWKTO_WIDGET_USER; + Configuration::updateValue($userKey, $this->context->employee->id); + + die(Tools::jsonEncode(['success' => TRUE])); + } + + /** + * Remove widget page ID and widget ID + * + * @return void + */ + public function ajaxProcessRemoveWidget() { + $keys = [ + TawkTo::TAWKTO_SELECTED_WIDGET, + TawkTo::TAWKTO_WIDGET_USER, + ]; + + foreach ($keys as $key) { + if (Shop::getContext() == Shop::CONTEXT_ALL) { + Configuration::updateValue($key, ''); + } + else { + // Configuration::deleteFromContext method cannot be used by + // 'All Shops' or the current shop context is 'CONTEXT_ALL'. + Configuration::deleteFromContext($key); + } } - public function ajaxProcessRemoveWidget() - { - $keys = array( - TawkTo::TAWKTO_SELECTED_WIDGET, - TawkTo::TAWKTO_WIDGET_USER - ); - - foreach ($keys as $key) { - if (Shop::getContext() == Shop::CONTEXT_ALL) { - Configuration::updateValue($key, ''); - } else { - // Configuration::deleteFromContext method cannot be used by - // 'All Shops' or the current shop context is 'CONTEXT_ALL'. - Configuration::deleteFromContext($key); + die(Tools::jsonEncode(['success' => TRUE])); + } + + /** + * Save visibility settings + * + * @return void + */ + public function ajaxProcessSetVisibility() { + $jsonOpts = [ + 'always_display' => FALSE, + 'show_onfrontpage' => FALSE, + 'show_oncategory' => FALSE, + 'show_onproduct' => FALSE, + + // default value needs to be a json encoded of an empty array + // since we're going to save a json encoded array later on. + 'show_oncustom' => json_encode([]), + + 'enable_visitor_recognition' => FALSE, + ]; + + $options = Tools::getValue('options'); + if (!empty($options)) { + $options = explode('&', $options); + foreach ($options as $post) { + [$column, $value] = explode('=', $post); + switch ($column) { + case 'show_oncustom': + // replace newlines and returns with comma, and convert to array for + // saving + $value = urldecode($value); + $value = str_ireplace(["\r\n", "\r", "\n"], ',', $value); + if (!empty($value)) { + $value = explode(",", $value); + $jsonOpts[$column] = json_encode($value); } + break; + + case 'show_onfrontpage': + case 'show_oncategory': + case 'show_onproduct': + case 'always_display': + case 'enable_visitor_recognition': + $jsonOpts[$column] = ($value == 1); + break; } - - die(Tools::jsonEncode(array('success' => true))); + } } + $key = TawkTo::TAWKTO_WIDGET_OPTS; + Configuration::updateValue($key, json_encode($jsonOpts)); - public function ajaxProcessSetVisibility() - { - $jsonOpts = array( - 'always_display' => false, - 'show_onfrontpage' => false, - 'show_oncategory' => false, - 'show_onproduct' => false, - - // default value needs to be a json encoded of an empty array - // since we're going to save a json encoded array later on. - 'show_oncustom' => json_encode(array()), - - 'enable_visitor_recognition' => false - ); - - $options = Tools::getValue('options'); - if (!empty($options)) { - $options = explode('&', $options); - foreach ($options as $post) { - list($column, $value) = explode('=', $post); - switch ($column) { - case 'show_oncustom': - // replace newlines and returns with comma, and convert to array for saving - $value = urldecode($value); - $value = str_ireplace(array("\r\n", "\r", "\n"), ',', $value); - if (!empty($value)) { - $value = explode(",", $value); - $jsonOpts[$column] = json_encode($value); - } - break; - case 'show_onfrontpage': - case 'show_oncategory': - case 'show_onproduct': - case 'always_display': - case 'enable_visitor_recognition': - $jsonOpts[$column] = ($value == 1); - break; - } - } - } - - $key = TawkTo::TAWKTO_WIDGET_OPTS; - Configuration::updateValue($key, json_encode($jsonOpts)); + die(Tools::jsonEncode(['success' => TRUE])); + } - die(Tools::jsonEncode(array('success' => true))); - } } diff --git a/prestashop1.6/index.php b/prestashop1.6/index.php index 2f5effc..aa04576 100644 --- a/prestashop1.6/index.php +++ b/prestashop1.6/index.php @@ -1,4 +1,5 @@ name = 'tawkto'; - $this->tab = 'front_office_features'; - $this->version = '1.3.0'; - $this->author = 'tawk.to'; - $this->need_instance = 0; - $this->ps_versions_compliancy = array('min' => '1.5', 'max' => '1.6'); - $this->dependencies = array('blockcart'); - - parent::__construct(); - - $this->displayName = $this->l('tawk.to'); - $this->description = $this->l('tawk.to live chat integration.'); - - $this->confirmUninstall = $this->l('Are you sure you want to uninstall?'); - - if (!Configuration::get('MYMODULE_NAME')) { - $this->warning = $this->l('No name provided'); - } +/** + * tawk.to module + */ +class Tawkto extends Module { + const TAWKTO_WIDGET_PAGE_ID = 'TAWKTO_WIDGET_PAGE_ID'; + const TAWKTO_WIDGET_WIDGET_ID = 'TAWKTO_WIDGET_WIDGET_ID'; + const TAWKTO_WIDGET_OPTS = 'TAWKTO_WIDGET_OPTS'; + const TAWKTO_WIDGET_USER = 'TAWKTO_WIDGET_USER'; + const TAWKTO_SELECTED_WIDGET = 'TAWKTO_SELECTED_WIDGET'; + + /** + * __construct + * + * @return void + */ + public function __construct() { + $this->name = 'tawkto'; + $this->tab = 'front_office_features'; + $this->version = '1.3.0'; + $this->author = 'tawk.to'; + $this->need_instance = 0; + $this->ps_versions_compliancy = ['min' => '1.5', 'max' => '1.6']; + $this->dependencies = ['blockcart']; + + parent::__construct(); + + $this->displayName = $this->l('tawk.to'); + $this->description = $this->l('tawk.to live chat integration.'); + + $this->confirmUninstall = $this->l('Are you sure you want to uninstall?'); + + if (!Configuration::get('MYMODULE_NAME')) { + $this->warning = $this->l('No name provided'); + } + } + + /** + * Install module + * + * @return boolean + */ + public function install() { + return parent::install() && $this->registerHook('footer') && $this->installTab(); + } + + /** + * Install tab + * + * @return boolean + */ + private function installTab() { + $tab = new Tab(); + $tab->active = 1; + $tab->class_name = 'AdminTawkto'; + $tab->name = []; + + foreach (Language::getLanguages(TRUE) as $lang) { + $tab->name[$lang['id_lang']] = 'tawk.to'; } - public function install() - { - return parent::install() && $this->registerHook('footer') && $this->installTab(); + $tab->id_parent = (int) Tab::getIdFromClassName('AdminAdmin'); + $tab->module = $this->name; + + return $tab->add(); + } + + /** + * Hook to add widget on page + * + * @return mixed|string + */ + public function hookDisplayFooter() { + $current_widget = self::getPropertyAndWidget(); + if (empty($current_widget)) { + return ''; } - private function installTab() - { - $tab = new Tab(); - $tab->active = 1; - $tab->class_name = 'AdminTawkto'; - $tab->name = array(); + $pageId = $current_widget['page_id']; + $widgetId = $current_widget['widget_id']; - foreach (Language::getLanguages(true) as $lang) { - $tab->name[$lang['id_lang']] = 'tawk.to'; - } + $result = Configuration::get(self::TAWKTO_WIDGET_OPTS); + $enable_visitor_recognition = TRUE; // default value + if ($result) { + $options = json_decode($result); - $tab->id_parent = (int)Tab::getIdFromClassName('AdminAdmin'); - $tab->module = $this->name; + if (isset($options->enable_visitor_recognition)) { + $enable_visitor_recognition = $options->enable_visitor_recognition; + } - return $tab->add(); - } + // prepare visibility + if (FALSE == $options->always_display) { + // show on specified urls + $show_pages = $this->getArrayFromJson($options->show_oncustom); - public function hookDisplayFooter() - { - $current_widget = self::getPropertyAndWidget(); - if (empty($current_widget)) { - return ''; + $show = FALSE; + if (UrlPatternMatcher::match($_SERVER['REQUEST_URI'], $show_pages)) { + $show = TRUE; } - $pageId = $current_widget['page_id']; - $widgetId = $current_widget['widget_id']; - - $result = Configuration::get(self::TAWKTO_WIDGET_OPTS); - $enable_visitor_recognition = true; // default value - if ($result) { - $options = json_decode($result); - - if (isset($options->enable_visitor_recognition)) { - $enable_visitor_recognition = $options->enable_visitor_recognition; + if (!$show) { + if ('index' == $this->context->controller->php_self) { + if ($options->show_onfrontpage) { + $show = TRUE; } - - // prepare visibility - if (false==$options->always_display) { - // show on specified urls - $show_pages = $this->getArrayFromJson($options->show_oncustom); - - $show = false; - if (UrlPatternMatcher::match($_SERVER['REQUEST_URI'], $show_pages)) { - $show = true; - } - - if (!$show) { - if ('index' == $this->context->controller->php_self) { - if ($options->show_onfrontpage) { - $show = true; - } - } - if ('category' == $this->context->controller->php_self) { - if ($options->show_oncategory) { - $show = true; - } - } - if ('product' == $this->context->controller->php_self) { - if ($options->show_onproduct) { - $show = true; - } - } - } - - if (!$show) { - return ''; - } + } + if ('category' == $this->context->controller->php_self) { + if ($options->show_oncategory) { + $show = TRUE; } + } + if ('product' == $this->context->controller->php_self) { + if ($options->show_onproduct) { + $show = TRUE; + } + } } - // add customer details as visitor info - $customer_name = null; - $customer_email = null; - if ($enable_visitor_recognition && !is_null($this->context->customer->id)) { - $customer = $this->context->customer; - $customer_name = $customer->firstname.' '.$customer->lastname; - $customer_email = $customer->email; + if (!$show) { + return ''; } - - $this->context->smarty->assign(array( - 'widget_id' => $widgetId, - 'page_id' => $pageId, - 'customer_name' => (!is_null($customer_name)) ? $customer_name : '', - 'customer_email' => (!is_null($customer_email)) ? $customer_email : '', - )); - - return $this->display(__FILE__, 'widget.tpl'); + } } - public function uninstall() - { - if (!parent::uninstall() || !$this->uninstallTab()) { - return false; - } + // add customer details as visitor info + $customer_name = NULL; + $customer_email = NULL; + if ($enable_visitor_recognition && !is_null($this->context->customer->id)) { + $customer = $this->context->customer; + $customer_name = $customer->firstname . ' ' . $customer->lastname; + $customer_email = $customer->email; + } - $keys = array( - self::TAWKTO_SELECTED_WIDGET, - self::TAWKTO_WIDGET_OPTS, - self::TAWKTO_WIDGET_USER - ); + $this->context->smarty->assign([ + 'widget_id' => $widgetId, + 'page_id' => $pageId, + 'customer_name' => (!is_null($customer_name)) ? $customer_name : '', + 'customer_email' => (!is_null($customer_email)) ? $customer_email : '', + ]); + + return $this->display(__FILE__, 'widget.tpl'); + } + + /** + * Uninstall module + * + * @return boolean + */ + public function uninstall() { + if (!parent::uninstall() || !$this->uninstallTab()) { + return FALSE; + } - foreach ($keys as $key) { - Configuration::deleteByName($key); - } + $keys = [ + self::TAWKTO_SELECTED_WIDGET, + self::TAWKTO_WIDGET_OPTS, + self::TAWKTO_WIDGET_USER, + ]; - return true; + foreach ($keys as $key) { + Configuration::deleteByName($key); } - public function uninstallTab() - { - $id_tab = (int)Tab::getIdFromClassName('AdminTawkto'); + return TRUE; + } - if ($id_tab) { - $tab = new Tab($id_tab); - return $tab->delete(); - } else { - return false; - } - } + /** + * Uninstall tab + * + * @return boolean + */ + public function uninstallTab() { + $id_tab = (int) Tab::getIdFromClassName('AdminTawkto'); - public function getContent() - { - Tools::redirectAdmin($this->context->link->getAdminLink('AdminTawkto')); + if ($id_tab) { + $tab = new Tab($id_tab); + return $tab->delete(); + } + else { + return FALSE; + } + } + + /** + * Redirect to tawk.to module + * + * @return void + */ + public function getContent() { + Tools::redirectAdmin($this->context->link->getAdminLink('AdminTawkto')); + } + + /** + * Get property ID and widget ID + * + * @return array[string]string + */ + public function getPropertyAndWidget() { + $current_widget = Configuration::get(self::TAWKTO_SELECTED_WIDGET); + if (empty($current_widget)) { + return NULL; } - public function getPropertyAndWidget() - { - $current_widget = Configuration::get(self::TAWKTO_SELECTED_WIDGET); - if (empty($current_widget)) { - return null; - } - - $current_widget = explode(':', $current_widget); - if (count($current_widget) < 2) { - // this means that something went wrong when saving the property and widget. - return null; - } + $current_widget = explode(':', $current_widget); + if (count($current_widget) < 2) { + // this means that something went wrong when saving the property and + // widget. + return NULL; + } - return array( - 'page_id' => $current_widget[0], - 'widget_id' => $current_widget[1] - ); + return [ + 'page_id' => $current_widget[0], + 'widget_id' => $current_widget[1], + ]; + } + + /** + * Convert JSON to array + * + * @param string|string[] $data Data. + * @return string[] + */ + private function getArrayFromJson($data) { + $arr = []; + if (is_string($data)) { + $data = json_decode($data); } - private function getArrayFromJson($data) - { - $arr = array(); - if (is_string($data)) { - $data = json_decode($data); - } + if (is_array($data)) { + $arr = $data; + } - if (is_array($data)) { - $arr = $data; - } + return $arr; + } - return $arr; - } } diff --git a/prestashop1.6/upgrade/Upgrade-1.2.0.php b/prestashop1.6/upgrade/Upgrade-1.2.0.php index 78361df..703613b 100644 --- a/prestashop1.6/upgrade/Upgrade-1.2.0.php +++ b/prestashop1.6/upgrade/Upgrade-1.2.0.php @@ -1,4 +1,5 @@ execute(join(' ', $sql)); //returns boolean value + // join sql array and execute + $result = $db->execute(implode(' ', $sql)); //returns boolean value - return $result; + return $result; } -function insert_records() -{ - $res = true; - - // modify global first - $res &= modify_widget(); +/** + * Insert records + * + * @return boolean + */ +function insert_records() { + $res = TRUE; - $shop_ids = Shop::getCompleteListOfShopsID(); + // modify global first + $res &= modify_widget(); - $updated_groups = array(); - foreach ($shop_ids as $shop_id) { - $shop_group_id = (int)Shop::getGroupFromShop($shop_id); + $shop_ids = Shop::getCompleteListOfShopsID(); - if (!in_array($shop_group_id, $updated_groups)) { - // update the group config - $res &= modify_widget($shop_group_id); - $updated_groups[] = $shop_group_id; - } + $updated_groups = []; + foreach ($shop_ids as $shop_id) { + $shop_group_id = (int) Shop::getGroupFromShop($shop_id); - // update the shop config - $res &= modify_widget($shop_group_id, $shop_id); + if (!in_array($shop_group_id, $updated_groups)) { + // update the group config + $res &= modify_widget($shop_group_id); + $updated_groups[] = $shop_group_id; } - return $res; -} + // update the shop config + $res &= modify_widget($shop_group_id, $shop_id); + } -function modify_widget($shop_group_id = null, $shop_id = null) -{ - if (isset($shop_id)) { - Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); - } elseif (isset($shop_group_id)) { - Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); - } else { - Shop::setContext(Shop::CONTEXT_ALL); - } + return $res; +} - $page_id = Configuration::get(TawkTo::TAWKTO_WIDGET_PAGE_ID, null, $shop_group_id, $shop_id); - $widget_id = Configuration::get(TawkTo::TAWKTO_WIDGET_WIDGET_ID, null, $shop_group_id, $shop_id); - return Configuration::updateValue( +/** + * Update widget settings + * + * @param null|integer $shop_group_id Shop group ID. + * @param null|integer $shop_id Shop ID. + * @return boolean + */ +function modify_widget($shop_group_id = NULL, $shop_id = NULL) { + if (isset($shop_id)) { + Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); + } + elseif (isset($shop_group_id)) { + Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); + } + else { + Shop::setContext(Shop::CONTEXT_ALL); + } + + $page_id = Configuration::get(TawkTo::TAWKTO_WIDGET_PAGE_ID, NULL, $shop_group_id, $shop_id); + $widget_id = Configuration::get(TawkTo::TAWKTO_WIDGET_WIDGET_ID, NULL, $shop_group_id, $shop_id); + return Configuration::updateValue( TawkTo::TAWKTO_SELECTED_WIDGET, - $page_id.':'.$widget_id, - false, + $page_id . ':' . $widget_id, + FALSE, $shop_group_id, $shop_id ); } -function remove_extras() -{ - // remove TAWKTO_WIDGET_PAGE_ID and TAWKTO_WIDGET_WIDGET_ID records - $res = Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_PAGE_ID); - $res &= Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_WIDGET_ID); - return $res; +/** + * Remove TAWKTO_WIDGET_PAGE_ID and TAWKTO_WIDGET_WIDGET_ID records + * + * @return boolean + */ +function remove_extras() { + // remove TAWKTO_WIDGET_PAGE_ID and TAWKTO_WIDGET_WIDGET_ID records + $res = Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_PAGE_ID); + $res &= Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_WIDGET_ID); + return $res; } diff --git a/prestashop1.6/upgrade/Upgrade-1.2.3.php b/prestashop1.6/upgrade/Upgrade-1.2.3.php index 9689134..06f1017 100644 --- a/prestashop1.6/upgrade/Upgrade-1.2.3.php +++ b/prestashop1.6/upgrade/Upgrade-1.2.3.php @@ -1,4 +1,5 @@ show_oncustom) && is_array($opts->show_oncustom) && $opts->show_oncustom === array()) { - $opts->show_oncustom = json_encode(array()); - } + // update the shop config + $res &= update_visibility_opts($shop_group_id, $shop_id); + } - if (isset($opts->hide_oncustom) && is_array($opts->hide_oncustom) && $opts->hide_oncustom === array()) { - $opts->hide_oncustom = json_encode(array()); - } + return $res; +} - return Configuration::updateValue( +/** + * Update visibility options + * + * @param null|integer $shop_group_id Shop group ID. + * @param null|integer $shop_id Shop ID. + * @return boolean + */ +function update_visibility_opts($shop_group_id = NULL, $shop_id = NULL) { + if (isset($shop_id)) { + Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); + } + elseif (isset($shop_group_id)) { + Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); + } + else { + Shop::setContext(Shop::CONTEXT_ALL); + } + + $opts = Configuration::get(TawkTo::TAWKTO_WIDGET_OPTS, NULL, $shop_group_id, $shop_id); + + if (!$opts) { + return FALSE; + } + + $opts = json_decode($opts); + + if (isset($opts->show_oncustom) && is_array($opts->show_oncustom) && $opts->show_oncustom === []) { + $opts->show_oncustom = json_encode([]); + } + + if (isset($opts->hide_oncustom) && is_array($opts->hide_oncustom) && $opts->hide_oncustom === []) { + $opts->hide_oncustom = json_encode([]); + } + + return Configuration::updateValue( TawkTo::TAWKTO_WIDGET_OPTS, json_encode($opts), - false, + FALSE, $shop_group_id, $shop_id ); diff --git a/prestashop1.6/upgrade/Upgrade-1.3.0.php b/prestashop1.6/upgrade/Upgrade-1.3.0.php index 9e3e9ce..4bb1ba5 100644 --- a/prestashop1.6/upgrade/Upgrade-1.3.0.php +++ b/prestashop1.6/upgrade/Upgrade-1.3.0.php @@ -1,4 +1,5 @@ show_oncustom)) { - $show_oncustom = json_decode($opts->show_oncustom); - if (is_array($show_oncustom)) { - $opts->show_oncustom = addWildcardToPatternList($show_oncustom); - } +/** + * Update visibility options + * + * @param null|integer $shop_group_id Shop group ID. + * @param null|integer $shop_id Shop ID. + * @return boolean + */ +function update_visibility_opts($shop_group_id = NULL, $shop_id = NULL) { + if (isset($shop_id)) { + Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); + } + elseif (isset($shop_group_id)) { + Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); + } + else { + Shop::setContext(Shop::CONTEXT_ALL); + } + + $opts = Configuration::get(TawkTo::TAWKTO_WIDGET_OPTS, NULL, $shop_group_id, $shop_id); + + if (!$opts) { + return FALSE; + } + + $opts = json_decode($opts); + + if (isset($opts->show_oncustom)) { + $show_oncustom = json_decode($opts->show_oncustom); + if (is_array($show_oncustom)) { + $opts->show_oncustom = add_wildcard_to_pattern_list($show_oncustom); } + } - if (isset($opts->hide_oncustom)) { - $hide_oncustom = json_decode($opts->hide_oncustom); - if (is_array($hide_oncustom)) { - $opts->hide_oncustom = addWildcardToPatternList($hide_oncustom); - } + if (isset($opts->hide_oncustom)) { + $hide_oncustom = json_decode($opts->hide_oncustom); + if (is_array($hide_oncustom)) { + $opts->hide_oncustom = add_wildcard_to_pattern_list($hide_oncustom); } + } - return Configuration::updateValue( + return Configuration::updateValue( TawkTo::TAWKTO_WIDGET_OPTS, json_encode($opts), - false, + FALSE, $shop_group_id, $shop_id ); } -function checkPatternListHasWildcard($patternList, $wildcard) { - foreach ($patternList as $pattern) { - if (strpos($pattern, $wildcard) > -1) { - return true; - } +/** + * Check pattern list for wildcard + * + * @param string[] $patternList List of patterns. + * @param string $wildcard Wildcard. + * @return boolean + */ +function check_pattern_list_has_wildcard(array $patternList, string $wildcard) { + foreach ($patternList as $pattern) { + if (strpos($pattern, $wildcard) > -1) { + return TRUE; } + } - return false; + return FALSE; } -function addWildcardToPatternList($patternList) -{ - $wildcard = PathHelper::get_wildcard(); - - if (checkPatternListHasWildcard($patternList, $wildcard)) { - return json_encode($patternList); +/** + * Add wildcard to pattern list + * + * @param string[] $patternList List of patterns. + * @return string|false + */ +function add_wildcard_to_pattern_list(array $patternList) { + $wildcard = PathHelper::get_wildcard(); + + if (check_pattern_list_has_wildcard($patternList, $wildcard)) { + return json_encode($patternList); + } + + $newPatternList = []; + $addedPatterns = []; + + foreach ($patternList as $pattern) { + if (empty($pattern)) { + continue; } - $newPatternList = []; - $addedPatterns = []; - - foreach ($patternList as $pattern) { - if (empty($pattern)) { - continue; - } - - $pattern = ltrim($pattern, PHP_EOL); - $pattern = trim($pattern); - - if (strpos($pattern, 'http://') !== 0 && - strpos($pattern, 'https://') !== 0 && - strpos($pattern, '/') !== 0 - ) { - // Check if the first part of the string is a host. - // If not, add a leading / so that the pattern - // matcher treats is as a path. - $firstPatternChunk = explode('/', $pattern)[0]; - - if (checkValidHost($firstPatternChunk) === false) { - $pattern = '/' . $pattern; - } - } - - $newPatternList[] = $pattern; - $newPattern = $pattern . '/' . $wildcard; - if (in_array($newPattern, $patternList, true)) { - continue; - } - - if (true === isset($addedPatterns[$newPattern])) { - continue; - } - - $newPatternList[] = $newPattern; - $addedPatterns[$newPattern] = true; + $pattern = ltrim($pattern, PHP_EOL); + $pattern = trim($pattern); + + if (strpos($pattern, 'http://') !== 0 && + strpos($pattern, 'https://') !== 0 && + strpos($pattern, '/') !== 0 + ) { + // Check if the first part of the string is a host. + // If not, add a leading / so that the pattern + // matcher treats is as a path. + $firstPatternChunk = explode('/', $pattern)[0]; + + if (check_valid_host($firstPatternChunk) === FALSE) { + $pattern = '/' . $pattern; + } } - // EOL for display purposes - return json_encode($newPatternList); -} - -function checkValidHost($host) { - // contains port - if (strpos($host, ':') < 0) { - return true; + $newPatternList[] = $pattern; + $newPattern = $pattern . '/' . $wildcard; + if (in_array($newPattern, $patternList, TRUE)) { + continue; } - // is localhost - if (strpos($host, 'localhost') === 0) { - return true; + if (TRUE === isset($addedPatterns[$newPattern])) { + continue; } - // gotten from https://forums.digitalpoint.com/threads/what-will-be-preg_match-for-domain-names.1953314/#post-15036873 - // but updated the ending regex part to include numbers so it also matches IPs. - $host_check_regex = '/^[a-zA-Z0-9]*((-|\.)?[a-zA-Z0-9])*\.([a-zA-Z0-9]{1,4})$/'; + $newPatternList[] = $newPattern; + $addedPatterns[$newPattern] = TRUE; + } - return preg_match($host_check_regex, $host) > 0; + // EOL for display purposes + return json_encode($newPatternList); +} + +/** + * Check if is hostname + * + * @param string $host Hostname. + * @return boolean + */ +function check_valid_host(string $host) { + // contains port + if (strpos($host, ':') < 0) { + return TRUE; + } + + // is localhost + if (strpos($host, 'localhost') === 0) { + return TRUE; + } + + // gotten from https://forums.digitalpoint.com/threads/what-will-be-preg_match-for-domain-names.1953314/#post-15036873 + // but updated the ending regex part to include numbers so it also matches + // IPs. + $host_check_regex = '/^[a-zA-Z0-9]*((-|\.)?[a-zA-Z0-9])*\.([a-zA-Z0-9]{1,4})$/'; + + return preg_match($host_check_regex, $host) > 0; } diff --git a/prestashop1.6/views/templates/hook/widget.tpl b/prestashop1.6/views/templates/hook/widget.tpl index 44b67a8..8d8cc76 100644 --- a/prestashop1.6/views/templates/hook/widget.tpl +++ b/prestashop1.6/views/templates/hook/widget.tpl @@ -16,7 +16,7 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) *} - - \ No newline at end of file + diff --git a/prestashop1.7/README.md b/prestashop1.7/README.md index c13c99e..ece6ae0 100644 --- a/prestashop1.7/README.md +++ b/prestashop1.7/README.md @@ -4,24 +4,32 @@ Free live chat widget for your site ## Description -The tawk.to Live Chat app makes it easy to monitor and chat with visitors on your website. Be there when they need you with unlimited messaging, ticketing and your own Knowledge Base — all 100% FREE. +The tawk.to Live Chat app makes it easy to monitor and chat with visitors on +your website. Be there when they need you with unlimited messaging, ticketing +and your own Knowledge Base — all 100% FREE. -Compatible with all modern browsers, tawk.to was created in response to the growing need for businesses to respond in real time, with real people. +Compatible with all modern browsers, tawk.to was created in response to the +growing need for businesses to respond in real time, with real people. -Never lose another lead or sale again — tawk.to offers iOS, Android, Windows and Mac OSX apps to keep you connected wherever you go. +Never lose another lead or sale again — tawk.to offers iOS, Android, Windows and +Mac OSX apps to keep you connected wherever you go. -Don’t have a tawk.to account yet? [Create one here.](https://www.tawk.to/?utm_source=prestashop&utm_medium=link&utm_campaign=signup) +Don’t have a tawk.to account yet? +[Create one here.](https://www.tawk.to/?utm_source=prestashop&utm_medium=link&utm_campaign=signup) ## Installation This section describes how to install the plugin and get it working. ### Module Installer -1. Download the `tawk-prestashop-1.7-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download the `tawk-prestashop-1.7-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Go to `Dashboard` -> `Modules` -> `Module Manager`. -3. Click `Upload a module`, upload the zip file, and the module will install automatically. +3. Click `Upload a module`, upload the zip file, and the module will install +automatically. ### Manual Installation -1. Download and extract the `tawk-prestashop-1.7-.zip` from [latest release.](https://github.com/tawk/tawk-prestashop/releases) +1. Download and extract the `tawk-prestashop-1.7-.zip` from +[latest release.](https://github.com/tawk/tawk-prestashop/releases) 2. Upload `tawkto` directory to the `/modules/` directory. 3. Go to `Dashboard` -> `Modules` -> `Module Catalog`. 4. Search for the `tawk.to` plugin and `install`. @@ -32,7 +40,8 @@ It is under `Dashboard` -> `More` -> `tawk.to`. ### Widget Configuration 1. Go to the configuration page. 2. Log in to your tawk.to account. -3. Select the property and the widget you want to place on your store and click `Use selected widget`. +3. Select the property and the widget you want to place on your store and click +`Use selected widget`. 4. The widget will now appear on your store. ## Frequently Asked Questions diff --git a/prestashop1.7/controllers/admin/AdminTawktoController.php b/prestashop1.7/controllers/admin/AdminTawktoController.php index f02088a..8afb374 100644 --- a/prestashop1.7/controllers/admin/AdminTawktoController.php +++ b/prestashop1.7/controllers/admin/AdminTawktoController.php @@ -1,4 +1,5 @@ bootstrap = true; - $this->display = 'view'; - - parent::__construct(); - $this->meta_title = $this->l('tawk.to'); - - if (!$this->module->active) { - Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome')); - } +/** + * Admin settings controller + */ +class AdminTawktoController extends ModuleAdminController { + + /** + * __construct + * + * @return void + */ + public function __construct() { + $this->bootstrap = TRUE; + $this->display = 'view'; + + parent::__construct(); + $this->meta_title = $this->l('tawk.to'); + + if (!$this->module->active) { + Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome')); } - - public function initToolBarTitle() - { - $this->toolbar_title[] = $this->l('tawk.to'); - $this->toolbar_title[] = $this->l('Widget'); + } + + /** + * Set toolbar title + * + * @return void + */ + public function initToolBarTitle() { + $this->toolbar_title[] = $this->l('tawk.to'); + $this->toolbar_title[] = $this->l('Widget'); + } + + /** + * Set toolbar actions + * + * @return mixed + */ + public function initToolbar() { + $r = parent::initToolbar(); + + if (isset($this->toolbar_btn)) { + unset($this->toolbar_btn['back']); } - - public function initToolbar() - { - $r = parent::initToolbar(); - - if (isset($this->toolbar_btn)) { - unset($this->toolbar_btn['back']); - } else { - unset($this->page_header_toolbar_btn['back']); - } - - return $r; + else { + unset($this->page_header_toolbar_btn['back']); } - public function renderView() - { - // get current shopId - $shop = Context::getContext()->shop; - $domain = $shop->domain; - - $optKey = TawkTo::TAWKTO_WIDGET_OPTS; - - // returns 'false' if retrieved none. - $displayOpts = Configuration::get($optKey); - if (!$displayOpts) { - $displayOpts = null; - } - $displayOpts = Tools::jsonDecode($displayOpts); - - $sameUser = true; // assuming there is only one admin by default - $empId = Configuration::get(TawkTo::TAWKTO_WIDGET_USER); - if ($this->context->employee->id != $empId && $empId) { - $sameUser = false; - } - - $currentWidget = TawkTo::getPropertyAndWidget(); - $pageId = ''; - $widgetId = ''; - if (!empty($currentWidget)) { - $pageId = $currentWidget['page_id']; - $widgetId = $currentWidget['widget_id']; - } - - $this->tpl_view_vars = array( - 'iframe_url' => $this->getIframeUrl(), - 'base_url' => $this->getBaseUrl(), - 'controller' => $this->context->link->getAdminLink('AdminTawkto'), - 'tab_id' => (int) $this->context->controller->id, - 'domain' => $domain, - 'display_opts' => $displayOpts, - 'page_id' => $pageId, - 'widget_id' => $widgetId, - 'same_user' => $sameUser - ); - - return parent::renderView(); + return $r; + } + + /** + * Render admin widget settings view + * + * @return string + */ + public function renderView() { + // get current shopId + $shop = Context::getContext()->shop; + $domain = $shop->domain; + + $optKey = TawkTo::TAWKTO_WIDGET_OPTS; + + // returns 'false' if retrieved none. + $displayOpts = Configuration::get($optKey); + if (!$displayOpts) { + $displayOpts = NULL; } + $displayOpts = Tools::jsonDecode($displayOpts); - private function getBaseUrl() - { - return 'https://plugins.tawk.to'; + $sameUser = TRUE; // assuming there is only one admin by default + $empId = Configuration::get(TawkTo::TAWKTO_WIDGET_USER); + if ($this->context->employee->id != $empId && $empId) { + $sameUser = FALSE; } - private function getIframeUrl() - { - $currentWidget = TawkTo::getPropertyAndWidget(); - $pageId = ''; - $widgetId = ''; - if (!empty($currentWidget)) { - $pageId = $currentWidget['page_id']; - $widgetId = $currentWidget['widget_id']; - } - - return $this->getBaseUrl() - .'/generic/widgets' - .'?currentPageId='.$pageId - .'¤tWidgetId='.$widgetId; + $currentWidget = TawkTo::getPropertyAndWidget(); + $pageId = ''; + $widgetId = ''; + if (!empty($currentWidget)) { + $pageId = $currentWidget['page_id']; + $widgetId = $currentWidget['widget_id']; } - private static function idsAreCorrect($pageId, $widgetId) - { - return preg_match('/^[0-9A-Fa-f]{24}$/', $pageId) === 1 && preg_match('/^[a-z0-9]{1,50}$/i', $widgetId) === 1; + $this->tpl_view_vars = [ + 'iframe_url' => $this->getIframeUrl(), + 'base_url' => $this->getBaseUrl(), + 'controller' => $this->context->link->getAdminLink('AdminTawkto'), + 'tab_id' => (int) $this->context->controller->id, + 'domain' => $domain, + 'display_opts' => $displayOpts, + 'page_id' => $pageId, + 'widget_id' => $widgetId, + 'same_user' => $sameUser, + ]; + + return parent::renderView(); + } + + /** + * Base plugin URL + * + * @return string + */ + private function getBaseUrl() { + return 'https://plugins.tawk.to'; + } + + /** + * Generates iframe URL + * + * @return string + */ + private function getIframeUrl() { + $currentWidget = TawkTo::getPropertyAndWidget(); + $pageId = ''; + $widgetId = ''; + if (!empty($currentWidget)) { + $pageId = $currentWidget['page_id']; + $widgetId = $currentWidget['widget_id']; } - public function ajaxProcessSetWidget() - { - if (!Tools::getIsset('pageId') || !Tools::getIsset('widgetId')) { - die(Tools::jsonEncode(array('success' => false))); - } - - $pageId = Tools::getValue('pageId'); - $widgetId = Tools::getValue('widgetId'); - if (!self::idsAreCorrect($pageId, $widgetId)) { - die(Tools::jsonEncode(array('success' => false))); - } - - $currentWidgetKey = TawkTo::TAWKTO_SELECTED_WIDGET; - Configuration::updateValue($currentWidgetKey, $pageId.':'.$widgetId); + return $this->getBaseUrl() + . '/generic/widgets?currentPageId=' . $pageId + . '¤tWidgetId=' . $widgetId; + } + + /** + * Validate page ID and widget ID + * + * @param string $pageId Page ID. + * @param string $widgetId Widget ID. + * @return integer|false + */ + private static function idsAreCorrect(string $pageId, string $widgetId) { + return preg_match('/^[0-9A-Fa-f]{24}$/', $pageId) === 1 && preg_match('/^[a-z0-9]{1,50}$/i', $widgetId) === 1; + } + + /** + * Save widget page ID and widget ID + * + * @return void + */ + public function ajaxProcessSetWidget() { + if (!Tools::getIsset('pageId') || !Tools::getIsset('widgetId')) { + die(Tools::jsonEncode(['success' => FALSE])); + } - $userKey = TawkTo::TAWKTO_WIDGET_USER; - Configuration::updateValue($userKey, $this->context->employee->id); + $pageId = Tools::getValue('pageId'); + $widgetId = Tools::getValue('widgetId'); + if (!self::idsAreCorrect($pageId, $widgetId)) { + die(Tools::jsonEncode(['success' => FALSE])); + } - die(Tools::jsonEncode(array('success' => true))); + $currentWidgetKey = TawkTo::TAWKTO_SELECTED_WIDGET; + Configuration::updateValue($currentWidgetKey, $pageId . ':' . $widgetId); + + $userKey = TawkTo::TAWKTO_WIDGET_USER; + Configuration::updateValue($userKey, $this->context->employee->id); + + die(Tools::jsonEncode(['success' => TRUE])); + } + + /** + * Remove widget page ID and widget ID + * + * @return void + */ + public function ajaxProcessRemoveWidget() { + $keys = [ + TawkTo::TAWKTO_SELECTED_WIDGET, + TawkTo::TAWKTO_WIDGET_USER, + ]; + + foreach ($keys as $key) { + if (Shop::getContext() == Shop::CONTEXT_ALL) { + Configuration::updateValue($key, ''); + } + else { + // Configuration::deleteFromContext method cannot be used by + // 'All Shops' or the current shop context is 'CONTEXT_ALL'. + Configuration::deleteFromContext($key); + } } - public function ajaxProcessRemoveWidget() - { - $keys = array( - TawkTo::TAWKTO_SELECTED_WIDGET, - TawkTo::TAWKTO_WIDGET_USER - ); - - foreach ($keys as $key) { - if (Shop::getContext() == Shop::CONTEXT_ALL) { - Configuration::updateValue($key, ''); - } else { - // Configuration::deleteFromContext method cannot be used by - // 'All Shops' or the current shop context is 'CONTEXT_ALL'. - Configuration::deleteFromContext($key); + die(Tools::jsonEncode(['success' => TRUE])); + } + + /** + * Save visibility settings + * + * @return void + */ + public function ajaxProcessSetVisibility() { + $jsonOpts = [ + 'always_display' => FALSE, + + // default value needs to be a json encoded of an empty array + // since we're going to save a json encoded array later on. + 'hide_oncustom' => json_encode([]), + + 'show_onfrontpage' => FALSE, + 'show_oncategory' => FALSE, + 'show_onproduct' => FALSE, + + // default value needs to be a json encoded of an empty array + // since we're going to save a json encoded array later on. + 'show_oncustom' => json_encode([]), + + 'enable_visitor_recognition' => FALSE, + ]; + + $options = Tools::getValue('options'); + if (!empty($options)) { + $options = explode('&', $options); + foreach ($options as $post) { + [$column, $value] = explode('=', $post); + switch ($column) { + case 'hide_oncustom': + case 'show_oncustom': + // replace newlines and returns with comma, and convert to array for + // saving + $value = urldecode($value); + $value = str_ireplace(["\r\n", "\r", "\n"], ',', $value); + if (!empty($value)) { + $value = explode(",", $value); + $jsonOpts[$column] = json_encode($value); } + break; + + case 'show_onfrontpage': + case 'show_oncategory': + case 'show_onproduct': + case 'always_display': + case 'enable_visitor_recognition': + $jsonOpts[$column] = ($value == 1); + break; } - - die(Tools::jsonEncode(array('success' => true))); + } } + $key = TawkTo::TAWKTO_WIDGET_OPTS; + Configuration::updateValue($key, json_encode($jsonOpts)); - public function ajaxProcessSetVisibility() - { - $jsonOpts = array( - 'always_display' => false, - - // default value needs to be a json encoded of an empty array - // since we're going to save a json encoded array later on. - 'hide_oncustom' => json_encode(array()), - - 'show_onfrontpage' => false, - 'show_oncategory' => false, - 'show_onproduct' => false, - - // default value needs to be a json encoded of an empty array - // since we're going to save a json encoded array later on. - 'show_oncustom' => json_encode(array()), - - 'enable_visitor_recognition' => false - ); - - $options = Tools::getValue('options'); - if (!empty($options)) { - $options = explode('&', $options); - foreach ($options as $post) { - list($column, $value) = explode('=', $post); - switch ($column) { - case 'hide_oncustom': - case 'show_oncustom': - // replace newlines and returns with comma, and convert to array for saving - $value = urldecode($value); - $value = str_ireplace(array("\r\n", "\r", "\n"), ',', $value); - if (!empty($value)) { - $value = explode(",", $value); - $jsonOpts[$column] = json_encode($value); - } - break; - case 'show_onfrontpage': - case 'show_oncategory': - case 'show_onproduct': - case 'always_display': - case 'enable_visitor_recognition': - $jsonOpts[$column] = ($value == 1); - break; - } - } - } + die(Tools::jsonEncode(['success' => TRUE])); + } - $key = TawkTo::TAWKTO_WIDGET_OPTS; - Configuration::updateValue($key, json_encode($jsonOpts)); - - die(Tools::jsonEncode(array('success' => true))); - } } diff --git a/prestashop1.7/index.php b/prestashop1.7/index.php index 2f5effc..aa04576 100644 --- a/prestashop1.7/index.php +++ b/prestashop1.7/index.php @@ -1,4 +1,5 @@ name = 'tawkto'; - $this->tab = 'front_office_features'; - $this->version = '1.3.0'; - $this->author = 'tawk.to'; - $this->need_instance = 0; - $this->ps_versions_compliancy = array('min' => '1.5', 'max' => '1.7'); - - parent::__construct(); - - $this->displayName = $this->l('tawk.to'); - $this->description = $this->l('tawk.to live chat integration.'); - - $this->confirmUninstall = $this->l('Are you sure you want to uninstall?'); - - if (!Configuration::get('MYMODULE_NAME')) { - $this->warning = $this->l('No name provided'); - } +/** + * tawk.to module + */ +class Tawkto extends Module { + const TAWKTO_WIDGET_PAGE_ID = 'TAWKTO_WIDGET_PAGE_ID'; + const TAWKTO_WIDGET_WIDGET_ID = 'TAWKTO_WIDGET_WIDGET_ID'; + const TAWKTO_WIDGET_OPTS = 'TAWKTO_WIDGET_OPTS'; + const TAWKTO_WIDGET_USER = 'TAWKTO_WIDGET_USER'; + const TAWKTO_SELECTED_WIDGET = 'TAWKTO_SELECTED_WIDGET'; + + /** + * __construct + * + * @return void + */ + public function __construct() { + $this->name = 'tawkto'; + $this->tab = 'front_office_features'; + $this->version = '1.3.0'; + $this->author = 'tawk.to'; + $this->need_instance = 0; + $this->ps_versions_compliancy = ['min' => '1.5', 'max' => '1.7']; + + parent::__construct(); + + $this->displayName = $this->l('tawk.to'); + $this->description = $this->l('tawk.to live chat integration.'); + + $this->confirmUninstall = $this->l('Are you sure you want to uninstall?'); + + if (!Configuration::get('MYMODULE_NAME')) { + $this->warning = $this->l('No name provided'); + } + } + + /** + * Install module + * + * @return boolean + */ + public function install() { + return parent::install() && $this->registerHook('displayFooter') && $this->installTab(); + } + + /** + * Install tab + * + * @return boolean + */ + private function installTab() { + $tab = new Tab(); + $tab->active = 1; + $tab->class_name = 'AdminTawkto'; + $tab->name = []; + + foreach (Language::getLanguages(TRUE) as $lang) { + $tab->name[$lang['id_lang']] = 'tawk.to'; } - public function install() - { - return parent::install() && $this->registerHook('displayFooter') && $this->installTab(); + $tab->id_parent = (int) Tab::getIdFromClassName('AdminAdmin'); + $tab->module = $this->name; + + return $tab->add(); + } + + /** + * Hook to add widget on page + * + * @return mixed|string + */ + public function hookDisplayFooter() { + $current_widget = self::getPropertyAndWidget(); + if (empty($current_widget)) { + return ''; } - private function installTab() - { - $tab = new Tab(); - $tab->active = 1; - $tab->class_name = 'AdminTawkto'; - $tab->name = array(); + $pageId = $current_widget['page_id']; + $widgetId = $current_widget['widget_id']; - foreach (Language::getLanguages(true) as $lang) { - $tab->name[$lang['id_lang']] = 'tawk.to'; - } + $result = Configuration::get(self::TAWKTO_WIDGET_OPTS); + $enable_visitor_recognition = TRUE; // default value + if ($result) { + $options = json_decode($result); + $current_page = (string) $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; - $tab->id_parent = (int) Tab::getIdFromClassName('AdminAdmin'); - $tab->module = $this->name; + if (isset($options->enable_visitor_recognition)) { + $enable_visitor_recognition = $options->enable_visitor_recognition; + } - return $tab->add(); - } + // prepare visibility + if (FALSE == $options->always_display) { + // show on specified urls + $show_pages = $this->getArrayFromJson($options->show_oncustom); - public function hookDisplayFooter() - { - $current_widget = self::getPropertyAndWidget(); - if (empty($current_widget)) { - return ''; + $show = FALSE; + if (UrlPatternMatcher::match($current_page, $show_pages)) { + $show = TRUE; } - $pageId = $current_widget['page_id']; - $widgetId = $current_widget['widget_id']; - - $result = Configuration::get(self::TAWKTO_WIDGET_OPTS); - $enable_visitor_recognition = true; // default value - if ($result) { - $options = json_decode($result); - $current_page = (string) $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; + if (!$show) { + if ('product' == $this->context->controller->php_self) { + if ($options->show_onproduct) { + $show = TRUE; + } + } - if (isset($options->enable_visitor_recognition)) { - $enable_visitor_recognition = $options->enable_visitor_recognition; + if ('category' == $this->context->controller->php_self) { + if ($options->show_oncategory) { + $show = TRUE; } + } - // prepare visibility - if (false==$options->always_display) { - // show on specified urls - $show_pages = $this->getArrayFromJson($options->show_oncustom); - - $show = false; - if (UrlPatternMatcher::match($current_page, $show_pages)) { - $show = true; - } - - if (!$show) { - if ('product' == $this->context->controller->php_self) { - if ($options->show_onproduct) { - $show = true; - } - } - - if ('category' == $this->context->controller->php_self) { - if ($options->show_oncategory) { - $show = true; - } - } - - if ('index' == $this->context->controller->php_self) { - if ($options->show_onfrontpage) { - $show = true; - } - } - } - - if (!$show) { - return ''; - } - } else { - // hide on specified urls - $hide_pages = $this->getArrayFromJson($options->hide_oncustom); - - $show = true; - if (UrlPatternMatcher::match($current_page, $hide_pages)) { - $show = false; - } - - if (!$show) { - return; - } + if ('index' == $this->context->controller->php_self) { + if ($options->show_onfrontpage) { + $show = TRUE; } + } } - // add customer details as visitor info - $customer_name = null; - $customer_email = null; - if ($enable_visitor_recognition && !is_null($this->context->customer->id)) { - $customer = $this->context->customer; - $customer_name = $customer->firstname.' '.$customer->lastname; - $customer_email = $customer->email; + if (!$show) { + return ''; } - - $this->context->smarty->assign(array( - 'widget_id' => $widgetId, - 'page_id' => $pageId, - 'customer_name' => (!is_null($customer_name)) ? $customer_name : '', - 'customer_email' => (!is_null($customer_email)) ? $customer_email : '', - )); - - return $this->display(__FILE__, 'widget.tpl'); - } - - public function uninstall() - { - if (!parent::uninstall() || !$this->uninstallTab()) { - return false; + } + else { + // hide on specified urls + $hide_pages = $this->getArrayFromJson($options->hide_oncustom); + + $show = TRUE; + if (UrlPatternMatcher::match($current_page, $hide_pages)) { + $show = FALSE; } - $keys = array( - self::TAWKTO_SELECTED_WIDGET, - self::TAWKTO_WIDGET_OPTS, - self::TAWKTO_WIDGET_USER - ); - - foreach ($keys as $key) { - Configuration::deleteByName($key); + if (!$show) { + return; } - - return true; + } } - public function uninstallTab() - { - $id_tab = (int)Tab::getIdFromClassName('AdminTawkto'); + // add customer details as visitor info + $customer_name = NULL; + $customer_email = NULL; + if ($enable_visitor_recognition && !is_null($this->context->customer->id)) { + $customer = $this->context->customer; + $customer_name = $customer->firstname . ' ' . $customer->lastname; + $customer_email = $customer->email; + } - if ($id_tab) { - $tab = new Tab($id_tab); - return $tab->delete(); - } else { - return false; - } + $this->context->smarty->assign([ + 'widget_id' => $widgetId, + 'page_id' => $pageId, + 'customer_name' => (!is_null($customer_name)) ? $customer_name : '', + 'customer_email' => (!is_null($customer_email)) ? $customer_email : '', + ]); + + return $this->display(__FILE__, 'widget.tpl'); + } + + /** + * Uninstall module + * + * @return boolean + */ + public function uninstall() { + if (!parent::uninstall() || !$this->uninstallTab()) { + return FALSE; } - public function getContent() - { - Tools::redirectAdmin($this->context->link->getAdminLink('AdminTawkto')); + $keys = [ + self::TAWKTO_SELECTED_WIDGET, + self::TAWKTO_WIDGET_OPTS, + self::TAWKTO_WIDGET_USER, + ]; + + foreach ($keys as $key) { + Configuration::deleteByName($key); } - public function getPropertyAndWidget() - { - $current_widget = Configuration::get(self::TAWKTO_SELECTED_WIDGET); - if (empty($current_widget)) { - return null; - } + return TRUE; + } - $current_widget = explode(':', $current_widget); - if (count($current_widget) < 2) { - // this means that something went wrong when saving the property and widget. - return null; - } + /** + * Uninstall tab + * + * @return boolean + */ + public function uninstallTab() { + $id_tab = (int) Tab::getIdFromClassName('AdminTawkto'); - return array( - 'page_id' => $current_widget[0], - 'widget_id' => $current_widget[1] - ); + if ($id_tab) { + $tab = new Tab($id_tab); + return $tab->delete(); + } + else { + return FALSE; + } + } + + /** + * Redirect to tawk.to module + * + * @return void + */ + public function getContent() { + Tools::redirectAdmin($this->context->link->getAdminLink('AdminTawkto')); + } + + /** + * Get property ID and widget ID + * + * @return array[string]string + */ + public function getPropertyAndWidget() { + $current_widget = Configuration::get(self::TAWKTO_SELECTED_WIDGET); + if (empty($current_widget)) { + return NULL; } - private function getArrayFromJson($data) - { - $arr = array(); - if (is_string($data)) { - $data = json_decode($data); - } + $current_widget = explode(':', $current_widget); + if (count($current_widget) < 2) { + // this means that something went wrong when saving the property and + // widget. + return NULL; + } - if (is_array($data)) { - $arr = $data; - } + return [ + 'page_id' => $current_widget[0], + 'widget_id' => $current_widget[1], + ]; + } + + /** + * Convert JSON to array + * + * @param string|string[] $data Data. + * @return string[] + */ + private function getArrayFromJson($data) { + $arr = []; + if (is_string($data)) { + $data = json_decode($data); + } - return $arr; + if (is_array($data)) { + $arr = $data; } + + return $arr; + } + } diff --git a/prestashop1.7/upgrade/Upgrade-1.2.0.php b/prestashop1.7/upgrade/Upgrade-1.2.0.php index 78361df..068fac8 100644 --- a/prestashop1.7/upgrade/Upgrade-1.2.0.php +++ b/prestashop1.7/upgrade/Upgrade-1.2.0.php @@ -1,4 +1,5 @@ execute(join(' ', $sql)); //returns boolean value + // join sql array and execute + $result = $db->execute(implode(' ', $sql)); //returns boolean value - return $result; + return $result; } -function insert_records() -{ - $res = true; - - // modify global first - $res &= modify_widget(); +/** + * Insert records + * + * @return boolean + */ +function insert_records() { + $res = TRUE; - $shop_ids = Shop::getCompleteListOfShopsID(); + // modify global first + $res &= modify_widget(); - $updated_groups = array(); - foreach ($shop_ids as $shop_id) { - $shop_group_id = (int)Shop::getGroupFromShop($shop_id); + $shop_ids = Shop::getCompleteListOfShopsID(); - if (!in_array($shop_group_id, $updated_groups)) { - // update the group config - $res &= modify_widget($shop_group_id); - $updated_groups[] = $shop_group_id; - } + $updated_groups = []; + foreach ($shop_ids as $shop_id) { + $shop_group_id = (int) Shop::getGroupFromShop($shop_id); - // update the shop config - $res &= modify_widget($shop_group_id, $shop_id); + if (!in_array($shop_group_id, $updated_groups)) { + // update the group config + $res &= modify_widget($shop_group_id); + $updated_groups[] = $shop_group_id; } - return $res; -} + // update the shop config + $res &= modify_widget($shop_group_id, $shop_id); + } -function modify_widget($shop_group_id = null, $shop_id = null) -{ - if (isset($shop_id)) { - Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); - } elseif (isset($shop_group_id)) { - Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); - } else { - Shop::setContext(Shop::CONTEXT_ALL); - } + return $res; +} - $page_id = Configuration::get(TawkTo::TAWKTO_WIDGET_PAGE_ID, null, $shop_group_id, $shop_id); - $widget_id = Configuration::get(TawkTo::TAWKTO_WIDGET_WIDGET_ID, null, $shop_group_id, $shop_id); - return Configuration::updateValue( +/** + * Update widget settings + * + * @param null|integer $shop_group_id Shop group ID. + * @param null|integer $shop_id Shop ID. + * @return boolean + */ +function modify_widget($shop_group_id = NULL, $shop_id = NULL) { + if (isset($shop_id)) { + Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); + } + elseif (isset($shop_group_id)) { + Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); + } + else { + Shop::setContext(Shop::CONTEXT_ALL); + } + + $page_id = Configuration::get(TawkTo::TAWKTO_WIDGET_PAGE_ID, NULL, $shop_group_id, $shop_id); + $widget_id = Configuration::get(TawkTo::TAWKTO_WIDGET_WIDGET_ID, NULL, $shop_group_id, $shop_id); + return Configuration::updateValue( TawkTo::TAWKTO_SELECTED_WIDGET, - $page_id.':'.$widget_id, - false, + $page_id . ':' . $widget_id, + FALSE, $shop_group_id, $shop_id ); } -function remove_extras() -{ - // remove TAWKTO_WIDGET_PAGE_ID and TAWKTO_WIDGET_WIDGET_ID records - $res = Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_PAGE_ID); - $res &= Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_WIDGET_ID); - return $res; +/** + * Remove TAWKTO_WIDGET_PAGE_ID and TAWKTO_WIDGET_WIDGET_ID records + * + * @return boolean + */ +function remove_extras() { + $res = Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_PAGE_ID); + $res &= Configuration::deleteByName(TawkTo::TAWKTO_WIDGET_WIDGET_ID); + return $res; } diff --git a/prestashop1.7/upgrade/Upgrade-1.2.3.php b/prestashop1.7/upgrade/Upgrade-1.2.3.php index 9689134..06f1017 100644 --- a/prestashop1.7/upgrade/Upgrade-1.2.3.php +++ b/prestashop1.7/upgrade/Upgrade-1.2.3.php @@ -1,4 +1,5 @@ show_oncustom) && is_array($opts->show_oncustom) && $opts->show_oncustom === array()) { - $opts->show_oncustom = json_encode(array()); - } + // update the shop config + $res &= update_visibility_opts($shop_group_id, $shop_id); + } - if (isset($opts->hide_oncustom) && is_array($opts->hide_oncustom) && $opts->hide_oncustom === array()) { - $opts->hide_oncustom = json_encode(array()); - } + return $res; +} - return Configuration::updateValue( +/** + * Update visibility options + * + * @param null|integer $shop_group_id Shop group ID. + * @param null|integer $shop_id Shop ID. + * @return boolean + */ +function update_visibility_opts($shop_group_id = NULL, $shop_id = NULL) { + if (isset($shop_id)) { + Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); + } + elseif (isset($shop_group_id)) { + Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); + } + else { + Shop::setContext(Shop::CONTEXT_ALL); + } + + $opts = Configuration::get(TawkTo::TAWKTO_WIDGET_OPTS, NULL, $shop_group_id, $shop_id); + + if (!$opts) { + return FALSE; + } + + $opts = json_decode($opts); + + if (isset($opts->show_oncustom) && is_array($opts->show_oncustom) && $opts->show_oncustom === []) { + $opts->show_oncustom = json_encode([]); + } + + if (isset($opts->hide_oncustom) && is_array($opts->hide_oncustom) && $opts->hide_oncustom === []) { + $opts->hide_oncustom = json_encode([]); + } + + return Configuration::updateValue( TawkTo::TAWKTO_WIDGET_OPTS, json_encode($opts), - false, + FALSE, $shop_group_id, $shop_id ); diff --git a/prestashop1.7/upgrade/Upgrade-1.3.0.php b/prestashop1.7/upgrade/Upgrade-1.3.0.php index 9e3e9ce..4bb1ba5 100644 --- a/prestashop1.7/upgrade/Upgrade-1.3.0.php +++ b/prestashop1.7/upgrade/Upgrade-1.3.0.php @@ -1,4 +1,5 @@ show_oncustom)) { - $show_oncustom = json_decode($opts->show_oncustom); - if (is_array($show_oncustom)) { - $opts->show_oncustom = addWildcardToPatternList($show_oncustom); - } +/** + * Update visibility options + * + * @param null|integer $shop_group_id Shop group ID. + * @param null|integer $shop_id Shop ID. + * @return boolean + */ +function update_visibility_opts($shop_group_id = NULL, $shop_id = NULL) { + if (isset($shop_id)) { + Shop::setContext(Shop::CONTEXT_SHOP, $shop_id); + } + elseif (isset($shop_group_id)) { + Shop::setContext(Shop::CONTEXT_GROUP, $shop_group_id); + } + else { + Shop::setContext(Shop::CONTEXT_ALL); + } + + $opts = Configuration::get(TawkTo::TAWKTO_WIDGET_OPTS, NULL, $shop_group_id, $shop_id); + + if (!$opts) { + return FALSE; + } + + $opts = json_decode($opts); + + if (isset($opts->show_oncustom)) { + $show_oncustom = json_decode($opts->show_oncustom); + if (is_array($show_oncustom)) { + $opts->show_oncustom = add_wildcard_to_pattern_list($show_oncustom); } + } - if (isset($opts->hide_oncustom)) { - $hide_oncustom = json_decode($opts->hide_oncustom); - if (is_array($hide_oncustom)) { - $opts->hide_oncustom = addWildcardToPatternList($hide_oncustom); - } + if (isset($opts->hide_oncustom)) { + $hide_oncustom = json_decode($opts->hide_oncustom); + if (is_array($hide_oncustom)) { + $opts->hide_oncustom = add_wildcard_to_pattern_list($hide_oncustom); } + } - return Configuration::updateValue( + return Configuration::updateValue( TawkTo::TAWKTO_WIDGET_OPTS, json_encode($opts), - false, + FALSE, $shop_group_id, $shop_id ); } -function checkPatternListHasWildcard($patternList, $wildcard) { - foreach ($patternList as $pattern) { - if (strpos($pattern, $wildcard) > -1) { - return true; - } +/** + * Check pattern list for wildcard + * + * @param string[] $patternList List of patterns. + * @param string $wildcard Wildcard. + * @return boolean + */ +function check_pattern_list_has_wildcard(array $patternList, string $wildcard) { + foreach ($patternList as $pattern) { + if (strpos($pattern, $wildcard) > -1) { + return TRUE; } + } - return false; + return FALSE; } -function addWildcardToPatternList($patternList) -{ - $wildcard = PathHelper::get_wildcard(); - - if (checkPatternListHasWildcard($patternList, $wildcard)) { - return json_encode($patternList); +/** + * Add wildcard to pattern list + * + * @param string[] $patternList List of patterns. + * @return string|false + */ +function add_wildcard_to_pattern_list(array $patternList) { + $wildcard = PathHelper::get_wildcard(); + + if (check_pattern_list_has_wildcard($patternList, $wildcard)) { + return json_encode($patternList); + } + + $newPatternList = []; + $addedPatterns = []; + + foreach ($patternList as $pattern) { + if (empty($pattern)) { + continue; } - $newPatternList = []; - $addedPatterns = []; - - foreach ($patternList as $pattern) { - if (empty($pattern)) { - continue; - } - - $pattern = ltrim($pattern, PHP_EOL); - $pattern = trim($pattern); - - if (strpos($pattern, 'http://') !== 0 && - strpos($pattern, 'https://') !== 0 && - strpos($pattern, '/') !== 0 - ) { - // Check if the first part of the string is a host. - // If not, add a leading / so that the pattern - // matcher treats is as a path. - $firstPatternChunk = explode('/', $pattern)[0]; - - if (checkValidHost($firstPatternChunk) === false) { - $pattern = '/' . $pattern; - } - } - - $newPatternList[] = $pattern; - $newPattern = $pattern . '/' . $wildcard; - if (in_array($newPattern, $patternList, true)) { - continue; - } - - if (true === isset($addedPatterns[$newPattern])) { - continue; - } - - $newPatternList[] = $newPattern; - $addedPatterns[$newPattern] = true; + $pattern = ltrim($pattern, PHP_EOL); + $pattern = trim($pattern); + + if (strpos($pattern, 'http://') !== 0 && + strpos($pattern, 'https://') !== 0 && + strpos($pattern, '/') !== 0 + ) { + // Check if the first part of the string is a host. + // If not, add a leading / so that the pattern + // matcher treats is as a path. + $firstPatternChunk = explode('/', $pattern)[0]; + + if (check_valid_host($firstPatternChunk) === FALSE) { + $pattern = '/' . $pattern; + } } - // EOL for display purposes - return json_encode($newPatternList); -} - -function checkValidHost($host) { - // contains port - if (strpos($host, ':') < 0) { - return true; + $newPatternList[] = $pattern; + $newPattern = $pattern . '/' . $wildcard; + if (in_array($newPattern, $patternList, TRUE)) { + continue; } - // is localhost - if (strpos($host, 'localhost') === 0) { - return true; + if (TRUE === isset($addedPatterns[$newPattern])) { + continue; } - // gotten from https://forums.digitalpoint.com/threads/what-will-be-preg_match-for-domain-names.1953314/#post-15036873 - // but updated the ending regex part to include numbers so it also matches IPs. - $host_check_regex = '/^[a-zA-Z0-9]*((-|\.)?[a-zA-Z0-9])*\.([a-zA-Z0-9]{1,4})$/'; + $newPatternList[] = $newPattern; + $addedPatterns[$newPattern] = TRUE; + } - return preg_match($host_check_regex, $host) > 0; + // EOL for display purposes + return json_encode($newPatternList); +} + +/** + * Check if is hostname + * + * @param string $host Hostname. + * @return boolean + */ +function check_valid_host(string $host) { + // contains port + if (strpos($host, ':') < 0) { + return TRUE; + } + + // is localhost + if (strpos($host, 'localhost') === 0) { + return TRUE; + } + + // gotten from https://forums.digitalpoint.com/threads/what-will-be-preg_match-for-domain-names.1953314/#post-15036873 + // but updated the ending regex part to include numbers so it also matches + // IPs. + $host_check_regex = '/^[a-zA-Z0-9]*((-|\.)?[a-zA-Z0-9])*\.([a-zA-Z0-9]{1,4})$/'; + + return preg_match($host_check_regex, $host) > 0; }