├── Resources ├── Public │ ├── Scss │ │ └── theme │ │ │ ├── example.scss │ │ │ ├── example.css │ │ │ ├── darkmode.scss │ │ │ ├── darkmode.css │ │ │ ├── funkylight.scss │ │ │ ├── funkylight.css │ │ │ ├── clean.css │ │ │ └── clean.scss │ ├── Images │ │ ├── logo.png │ │ ├── expand-more.svg │ │ ├── close.svg │ │ ├── edit-square-gray.svg │ │ └── edit-square-white.svg │ ├── Icons │ │ ├── relation.gif │ │ ├── tx_cfcookiemanager_domain_model_conntentoverride.gif │ │ ├── tx_cfcookiemanager_domain_model_variables.svg │ │ ├── tx_cfcookiemanager_domain_model_cookiefrontend.svg │ │ ├── tx_cfcookiemanager_domain_model_cookieservice.svg │ │ ├── tx_cfcookiemanager_domain_model_scans.svg │ │ ├── tx_cfcookiemanager_domain_model_cookiecartegories.svg │ │ ├── tx_cfcookiemanager_domain_model_externalscripts.svg │ │ ├── tx_cfcookiemanager_domain_model_cookie.svg │ │ └── backend │ │ │ └── position │ │ │ ├── settings │ │ │ ├── settings_links.svg │ │ │ ├── settings_rechts.svg │ │ │ └── settings_mitte.svg │ │ │ └── consent │ │ │ ├── modal_links_oben.svg │ │ │ ├── modal_links_unten.svg │ │ │ ├── modal_mitte_oben.svg │ │ │ ├── modal_rechts_oben.svg │ │ │ ├── modal_unten_mitte.svg │ │ │ ├── modal_links_mitte.svg │ │ │ ├── modal_mitte_mitte.svg │ │ │ ├── modal_rechts_mitte.svg │ │ │ └── modal_rechts_unten.svg │ ├── Backend │ │ └── Css │ │ │ ├── mixins.scss │ │ │ ├── variables.scss │ │ │ ├── BackendModal.scss │ │ │ ├── BackendModal.css │ │ │ └── bootstrap-tour.css │ └── JavaScript │ │ ├── TutorialTours │ │ ├── TourManager.js │ │ ├── TourFunctions.js │ │ └── CategoryTour.js │ │ ├── Tracking.js │ │ ├── Backend │ │ ├── initCookieBackend.js │ │ └── BackendAjax │ │ │ └── ThumbnailService.js │ │ └── FormEngine │ │ └── Element │ │ ├── CfSelectMultipleSideBySideElement.js │ │ └── Extra │ │ └── SelectBoxFilter.js ├── Static │ ├── scriptblocker.html │ ├── settingsmodal_category.html │ ├── consentmodal.html │ └── settingsmodal.html └── Private │ ├── Layouts │ └── Default.html │ ├── .htaccess │ ├── Language │ ├── locallang_cookiesettings.xlf │ ├── da.locallang_cookiesettings.xlf │ ├── da.locallang.xlf │ ├── locallang.xlf │ └── de.locallang.xlf │ ├── Templates │ └── CookieFrontend │ │ ├── List.html │ │ └── CookieList.html │ └── Partials │ └── BackendTabs │ ├── frontend.html │ ├── categories.html │ ├── administration.html │ └── services.html ├── Configuration ├── Sets │ └── CfCookiemanager │ │ ├── setup.typoscript │ │ ├── constants.typoscript │ │ └── config.yaml ├── JavaScriptModules.php ├── page.tsconfig ├── RequestMiddlewares.php ├── TCA │ └── Overrides │ │ ├── tt_content.php │ │ ├── tx_cfcookiemanager_domain_model_variables.php │ │ ├── sys_template.php │ │ └── tx_cfcookiemanager_domain_model_cookiecartegories.php ├── TsConfig │ └── Page │ │ └── Mod │ │ └── Wizards │ │ └── CookieList.tsconfig ├── Backend │ ├── Modules.php │ ├── DashboardWidgets.yaml │ └── AjaxRoutes.php ├── Services.yaml └── Icons.php ├── Documentation ├── Images │ ├── Ui │ │ ├── ui.png │ │ ├── backend.png │ │ ├── backend_categories.png │ │ ├── backend_consentmodal.png │ │ ├── backend_servicescript.png │ │ ├── backend_settingsmodal.png │ │ ├── frontend_consentmodal.png │ │ ├── backend_servicedetailview.png │ │ ├── backend_categoriesdetailview.png │ │ ├── backend_cookie_service_provider.png │ │ └── backend_servicevariableprovider.png │ ├── cookie_settings.png │ ├── IntroductionPackage.png │ ├── UserManual │ │ └── BackendView.png │ ├── Installation │ │ └── installation_screen.png │ ├── AdministratorManual │ │ └── ExtensionManager.png │ └── Configuration │ │ ├── backend_cookie_categories.png │ │ ├── backend_after_first_install.png │ │ └── ConsentMode │ │ ├── consent_mode_debug.png │ │ ├── consent_mode_start.png │ │ ├── consent_mode_debug_init.png │ │ ├── consent_mode_debug_optin.png │ │ ├── consent_mode_debug_optout.png │ │ └── consent_mode_administration.png ├── Sitemap.rst ├── docker-compose.yml ├── KnownProblems │ └── Index.rst ├── Includes.txt ├── Configuration │ ├── CookieCategories │ │ └── Index.rst │ ├── Index.rst │ ├── FrontendSettings │ │ └── Index.rst │ ├── ExtensionSettings │ │ └── Index.rst │ └── AutoConfiguration │ │ └── Index.rst ├── Developer │ ├── ExtensionDevelopment │ │ └── Index.rst │ ├── EventDispatcher │ │ └── Index.rst │ └── CustomServices │ │ └── Index.rst ├── Introduction │ └── Index.rst ├── Index.rst └── Installation │ └── Index.rst ├── ext_conf_template.txt ├── .gitignore ├── phpstan.neon ├── .github ├── dependabot.yml └── workflows │ ├── core13.yml │ ├── core14.yml │ └── publish.yml ├── Tests ├── Acceptance │ ├── Fixtures │ │ └── SystemConfiguration │ │ │ └── Sites │ │ │ └── ensite │ │ │ └── config.yaml │ ├── Support │ │ ├── BackendTester.php │ │ └── Extension │ │ │ └── BackendEnvironment.php │ ├── Backend.suite.yml │ └── Backend │ │ └── Frontend │ │ └── CookieFrontendCest.php ├── codeception.yml ├── Functional │ └── BasicTest.php └── Unit │ ├── Domain │ └── Model │ │ ├── ExternalScriptsTest.php │ │ └── VariablesTest.php │ └── Utility │ └── ContentScriptBlockerTest.php ├── ext_tables.php ├── Classes ├── EventListener │ └── AddIntroJsModule.php ├── Updates │ └── PluginListToCTypeUpdateWizard.php ├── Domain │ ├── Repository │ │ ├── VariablesRepository.php │ │ └── CookieRepository.php │ └── Model │ │ ├── Variables.php │ │ └── ExternalScripts.php ├── Event │ └── ClassifyContentEvent.php ├── Controller │ └── BackendAjax │ │ └── ThumbnailController.php ├── Widgets │ └── Provider │ │ ├── ConsentTrackingDonutAcceptTypes.php │ │ └── ConsentTrackingDataProvider.php ├── Middleware │ └── ModifyHtmlContent.php └── Service │ └── SiteService.php ├── ext_emconf.php ├── Build └── phpunit │ ├── FunctionalTestsBootstrap.php │ ├── UnitTests.xml │ └── FunctionalTests.xml ├── ext_localconf.php └── composer.json /Resources/Public/Scss/theme/example.scss: -------------------------------------------------------------------------------- 1 | :root{ 2 | --cc-font-family: Verdana, sans-serif, monospace; 3 | } -------------------------------------------------------------------------------- /Configuration/Sets/CfCookiemanager/setup.typoscript: -------------------------------------------------------------------------------- 1 | @import 'EXT:cf_cookiemanager/Configuration/TypoScript/setup.typoscript' -------------------------------------------------------------------------------- /Documentation/Images/Ui/ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/ui.png -------------------------------------------------------------------------------- /ext_conf_template.txt: -------------------------------------------------------------------------------- 1 | ############## 2 | ### PAGETS ### 3 | ############## 4 | ## Moved to SiteSet and Constants since 1.9.0 -------------------------------------------------------------------------------- /Resources/Public/Images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Resources/Public/Images/logo.png -------------------------------------------------------------------------------- /Configuration/Sets/CfCookiemanager/constants.typoscript: -------------------------------------------------------------------------------- 1 | @import 'EXT:cf_cookiemanager/Configuration/TypoScript/constants.typoscript' -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend.png -------------------------------------------------------------------------------- /Resources/Public/Icons/relation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Resources/Public/Icons/relation.gif -------------------------------------------------------------------------------- /Documentation/Images/cookie_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/cookie_settings.png -------------------------------------------------------------------------------- /Documentation/Images/IntroductionPackage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/IntroductionPackage.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_categories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_categories.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_consentmodal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_consentmodal.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_servicescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_servicescript.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_settingsmodal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_settingsmodal.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/frontend_consentmodal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/frontend_consentmodal.png -------------------------------------------------------------------------------- /Documentation/Images/UserManual/BackendView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/UserManual/BackendView.png -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/example.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-font-family: Verdana, sans-serif, monospace; 3 | } 4 | 5 | /*# sourceMappingURL=example.css.map */ 6 | -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_servicedetailview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_servicedetailview.png -------------------------------------------------------------------------------- /Configuration/Sets/CfCookiemanager/config.yaml: -------------------------------------------------------------------------------- 1 | name: CodingFreaks/cf-cookiemanager 2 | label: CodingFreaks Cookie Manager Site Configuration (Default) 3 | dependencies: [] -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_categoriesdetailview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_categoriesdetailview.png -------------------------------------------------------------------------------- /Documentation/Images/Installation/installation_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Installation/installation_screen.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_cookie_service_provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_cookie_service_provider.png -------------------------------------------------------------------------------- /Documentation/Images/Ui/backend_servicevariableprovider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Ui/backend_servicevariableprovider.png -------------------------------------------------------------------------------- /Documentation/Images/AdministratorManual/ExtensionManager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/AdministratorManual/ExtensionManager.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/backend_cookie_categories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/backend_cookie_categories.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/backend_after_first_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/backend_after_first_install.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/ConsentMode/consent_mode_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/ConsentMode/consent_mode_debug.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/ConsentMode/consent_mode_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/ConsentMode/consent_mode_start.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/ConsentMode/consent_mode_debug_init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/ConsentMode/consent_mode_debug_init.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/ConsentMode/consent_mode_debug_optin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/ConsentMode/consent_mode_debug_optin.png -------------------------------------------------------------------------------- /Documentation/Images/Configuration/ConsentMode/consent_mode_debug_optout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/ConsentMode/consent_mode_debug_optout.png -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_conntentoverride.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Resources/Public/Icons/tx_cfcookiemanager_domain_model_conntentoverride.gif -------------------------------------------------------------------------------- /Documentation/Images/Configuration/ConsentMode/consent_mode_administration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eibiflo/cf_cookiemanager/HEAD/Documentation/Images/Configuration/ConsentMode/consent_mode_administration.png -------------------------------------------------------------------------------- /Documentation/Sitemap.rst: -------------------------------------------------------------------------------- 1 | :template: sitemap.html 2 | 3 | .. _sitemap: 4 | 5 | ======= 6 | Sitemap 7 | ======= 8 | 9 | .. template 'sitemap.html' will insert the toctree as a sitemap here below normal contents 10 | -------------------------------------------------------------------------------- /Resources/Static/scriptblocker.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /Resources/Private/Layouts/Default.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | -------------------------------------------------------------------------------- /Configuration/JavaScriptModules.php: -------------------------------------------------------------------------------- 1 | ['core', 'backend'], 5 | 'imports' => [ 6 | '@codingfreaks/cf-cookiemanager/' => 'EXT:cf_cookiemanager/Resources/Public/JavaScript/', 7 | ], 8 | ]; -------------------------------------------------------------------------------- /Documentation/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | t3docmake: 4 | image: t3docs/render-documentation:latest 5 | command: makehtml 6 | volumes: 7 | - ./:/PROJECT:ro 8 | - ./Documentation-GENERATED-temp:/RESULT -------------------------------------------------------------------------------- /Configuration/page.tsconfig: -------------------------------------------------------------------------------- 1 | @import 'EXT:cf_cookiemanager/Configuration/TsConfig/Page/Mod/Wizards/CookieList.tsconfig' 2 | 3 | templates.codingfreaks/cf-cookiemanager { 4 | 1643293191 = codingfreaks/cf-cookiemanager:Resources/Private/Backend 5 | } -------------------------------------------------------------------------------- /Resources/Private/.htaccess: -------------------------------------------------------------------------------- 1 | # Apache < 2.3 2 | 3 | Order allow,deny 4 | Deny from all 5 | Satisfy All 6 | 7 | 8 | # Apache >= 2.3 9 | 10 | Require all denied 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .Build/ 3 | Build/node_modules/ 4 | composer.lock 5 | var/ 6 | Build/testing-docker/.env 7 | Build/phpunit/.phpunit.result.cache 8 | .php_cs.cache 9 | .php-cs-fixer.cache 10 | Documentation-GENERATED-temp/ 11 | .env 12 | public 13 | .vscode 14 | .cache/ 15 | Web 16 | .github 17 | composer.json.testing -------------------------------------------------------------------------------- /Documentation/KnownProblems/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | .. _known-problems: 4 | 5 | ============== 6 | Known Problems 7 | ============== 8 | 9 | Use this section for informing about any type of problem. 10 | ---- 11 | 12 | * You can not eat cookies with this Extension. (This is a known problem of the cookiemonster) 13 | -------------------------------------------------------------------------------- /Configuration/RequestMiddlewares.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'codingfreaks/cf-cookiemanager/gdprhook' => [ 6 | 'target' => \CodingFreaks\CfCookiemanager\Middleware\ModifyHtmlContent::class, 7 | 'after' => [ 8 | 'typo3/cms-frontend/content-length-headers' 9 | ], 10 | ], 11 | ] 12 | ]; -------------------------------------------------------------------------------- /Resources/Public/Backend/Css/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin dark-mode { 2 | // Expliziter Dark-Mode 3 | [data-color-scheme="dark"] & { 4 | @content; 5 | } 6 | 7 | // Auto-Modus mit System-Dark-Mode 8 | @media (prefers-color-scheme: dark) { 9 | [data-color-scheme="auto"] & { 10 | @content; 11 | } 12 | [data-theme="auto"] & { 13 | @content; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | parallel: 3 | maximumNumberOfProcesses: 5 4 | 5 | level: 3 6 | 7 | bootstrapFiles: 8 | - .Build/vendor/autoload.php 9 | 10 | paths: 11 | - Classes 12 | - Configuration 13 | - Tests 14 | 15 | scanDirectories: 16 | - Classes 17 | - Configuration 18 | - Tests 19 | 20 | strictRules: 21 | disallowedConstructs: false -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/tt_content.php: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Resources/Public/Backend/Css/variables.scss: -------------------------------------------------------------------------------- 1 | $background-light: #EBEBEB; 2 | $background-dark: #333; 3 | $background-lighter: #d2d2d2; 4 | $background-darker: #4D4D4D; 5 | $text-light: #4B4B4B; 6 | $text-dark: #fff; 7 | $border-light: rgba(197, 221, 243, 0.61); 8 | $border-dark: #444; 9 | 10 | $tab-gray-active: #2F2F2F; 11 | $tab-gray: #4D4D4D; 12 | $tab-gray-light: #d2d2d2; 13 | $tab-gray-light-active: #aeaeae; 14 | 15 | 16 | $highlight: #9BB51C; 17 | $highlight-dark: #3f4c00; 18 | -------------------------------------------------------------------------------- /Tests/Acceptance/Fixtures/SystemConfiguration/Sites/ensite/config.yaml: -------------------------------------------------------------------------------- 1 | base: 'http://web/typo3temp/var/tests/acceptance' 2 | #Add web to your Hosts file with "127.0.0.1 web" 3 | languages: 4 | - 5 | title: Enlisch 6 | enabled: true 7 | locale: en-US 8 | hreflang: en-US 9 | base: / 10 | websiteTitle: 'Cookie Frontend Website' 11 | navigationTitle: 'Cookie Frontend Website Nav Title' 12 | flag: en-us-gb 13 | languageId: 0 14 | rootPageId: 1 15 | websiteTitle: '' 16 | -------------------------------------------------------------------------------- /Documentation/Includes.txt: -------------------------------------------------------------------------------- 1 | .. This is 'Includes.txt'. It is included at the very top of each and 2 | every ReST source file in THIS documentation project (= manual). 3 | 4 | .. role:: aspect (emphasis) 5 | .. role:: html(code) 6 | .. role:: js(code) 7 | .. role:: php(code) 8 | .. role:: sep (strong) 9 | .. role:: sql(code) 10 | .. role:: typoscript(code) 11 | .. role:: yaml(code) 12 | 13 | .. role:: ts(typoscript) 14 | :class: typoscript 15 | 16 | .. default-role:: code 17 | .. highlight:: php 18 | -------------------------------------------------------------------------------- /Resources/Public/Images/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_variables.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tests/codeception.yml: -------------------------------------------------------------------------------- 1 | namespace: CodingFreaks\CfCookiemanager\Tests\Acceptance\Support 2 | paths: 3 | tests: Acceptance 4 | data: . 5 | output: ../.Build/public/typo3temp/var/tests/AcceptanceReports 6 | support: Acceptance/Support 7 | settings: 8 | colors: true 9 | memory_limit: 1024M 10 | extensions: 11 | enabled: 12 | - Codeception\Extension\RunFailed 13 | - Codeception\Extension\Recorder 14 | modules: 15 | enabled: 16 | - Filesystem 17 | #- TYPO3\CMS\Core\Tests\Acceptance\Support\Helper\Config 18 | params: 19 | #- parameters.yml 20 | - env -------------------------------------------------------------------------------- /ext_tables.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | Cookie Settings 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/Static/settingsmodal_category.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 10 |
11 |
12 |
13 |
-------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_cookiefrontend.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Documentation/Configuration/CookieCategories/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | ============= 5 | Cookie Categories 6 | ============= 7 | 8 | A category is defined as a broad term. 9 | 10 | Services are assigned to each category. 11 | 12 | .. figure:: ../../Images/Configuration/backend_cookie_categories.png 13 | :class: with-shadow 14 | :alt: Backend 15 | :width: 100% 16 | 17 | 18 | Example 19 | --------------------- 20 | 21 | Example: :guilabel:`External Media` contains :guilabel:`Youtube` and :guilabel:`Vimeo` 22 | 23 | .. figure:: ../../Images/Ui/backend_categoriesdetailview.png 24 | :class: with-shadow 25 | :alt: Backend 26 | :width: 100% 27 | 28 | 29 | -------------------------------------------------------------------------------- /Resources/Public/Backend/Css/BackendModal.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | 4 | .cf-cookiemanager-changes-modal-list{ 5 | 6 | } 7 | 8 | .cf-cookiemanager-changes-modal-listitem{ 9 | background: $background-lighter; 10 | margin-bottom: 20px; 11 | padding: 20px; 12 | 13 | @include dark-mode { 14 | background: $background-darker; 15 | } 16 | 17 | 18 | strong{ 19 | font-size: 20px; 20 | } 21 | 22 | .cf-cookiemanager-changes-modal-changes-api,.cf-cookiemanager-changes-modal-changes-local{ 23 | display: flex; 24 | font-weight: bold; 25 | font-size: 14px; 26 | > div{ 27 | margin-left: 10px; 28 | font-weight: normal; 29 | } 30 | } 31 | 32 | 33 | 34 | } -------------------------------------------------------------------------------- /Resources/Static/consentmodal.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Configuration/TsConfig/Page/Mod/Wizards/CookieList.tsconfig: -------------------------------------------------------------------------------- 1 | mod.wizards { 2 | newContentElement.wizardItems { 3 | plugins { 4 | elements { 5 | cfcookiemanager_cookielist { 6 | iconIdentifier = cfcookiemanager-cookie-list 7 | title = LLL:EXT:cf_cookiemanager/Resources/Private/Language/locallang_db.xlf:cookieList_title 8 | description = LLL:EXT:cf_cookiemanager/Resources/Private/Language/locallang_db.xlf:cookieList_description 9 | tt_content_defValues { 10 | CType = cfcookiemanager_cookielist 11 | } 12 | } 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/tx_cfcookiemanager_domain_model_variables.php: -------------------------------------------------------------------------------- 1 | true, 5 | 'label' => 'LLL:EXT:cf_cookiemanager/Resources/Private/Language/locallang_db.xlf:tx_cfcookiemanager_domain_model_variables.identifier', 6 | "description"=> "if your Variable is not shown, Save the Record and refresh the form.", 7 | "config" => [ 8 | 'type' => 'select', 9 | 'renderType' => 'selectSingle', 10 | "items" => [ 11 | ["label"=>" " ,"value" =>" "], 12 | ], 13 | 'itemsProcFunc' => 'CodingFreaks\CfCookiemanager\Utility\HelperUtility->getVariablesFromItem', 14 | ] 15 | ]; -------------------------------------------------------------------------------- /Resources/Private/Language/da.locallang_cookiesettings.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | Cookie Settings 12 | Cookieindstillinger 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Classes/EventListener/AddIntroJsModule.php: -------------------------------------------------------------------------------- 1 | addCssFile('EXT:cf_cookiemanager/Resources/Public/Backend/Css/bootstrap-tour.css'); 17 | $pageRenderer->loadJavaScriptModule('@codingfreaks/cf-cookiemanager/TutorialTours/TourManager.js'); 18 | } 19 | } -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/sys_template.php: -------------------------------------------------------------------------------- 1 | getMajorVersion() < 13) { 15 | \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('cf_cookiemanager', 'Configuration/TypoScript', 'Coding Freaks Cookie Manager'); 16 | } 17 | }); 18 | */ 19 | -------------------------------------------------------------------------------- /Tests/Functional/BasicTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/darkmode.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-bg: #181b1d; 3 | --cc-text: #d8e5ea; 4 | --cc-btn-primary-bg: #a6c4dd; 5 | --cc-btn-primary-text: #000; 6 | --cc-btn-primary-hover-bg: #c2dff7; 7 | --cc-btn-secondary-bg: #33383c; 8 | --cc-btn-secondary-text: var(--cc-text); 9 | --cc-btn-secondary-hover-bg: #3e454a; 10 | --cc-toggle-bg-off: #667481; 11 | --cc-toggle-bg-on: var(--cc-btn-primary-bg); 12 | --cc-toggle-bg-readonly: #454c54; 13 | --cc-toggle-knob-bg: var(--cc-cookie-category-block-bg); 14 | --cc-toggle-knob-icon-color: var(--cc-bg); 15 | --cc-block-text: #b3bfc5; 16 | --cc-cookie-category-block-bg: #23272a; 17 | --cc-cookie-category-block-bg-hover: #2b3035; 18 | --cc-section-border: #292d31; 19 | --cc-cookie-table-border: #2b3035; 20 | --cc-webkit-scrollbar-bg: #667481; 21 | --cc-webkit-scrollbar-bg-hover: #9199a0 22 | } -------------------------------------------------------------------------------- /ext_emconf.php: -------------------------------------------------------------------------------- 1 | 'Coding Freaks Cookie Manager', 5 | 'description' => 'Manage cookies, scripts, and GDPR compliance on your Typo3 website with CodingFreaks Typo3 Cookie Manager. Customize cookie banners, streamline workflow, and enhance user experience. Ensure GDPR compliance and take control of cookie management with our Typo3 cookie management extension. Visit the official Typo3 Documentation page to learn more.', 6 | 'category' => 'plugin', 7 | 'author' => 'Florian Eibisberger', 8 | 'author_email' => '', 9 | 'state' => 'stable', 10 | 'clearCacheOnLoad' => 0, 11 | 'version' => '1.9.0', 12 | 'constraints' => [ 13 | 'depends' => [ 14 | 'typo3' => '13.5.99-14.4.99' 15 | ], 16 | 'conflicts' => [], 17 | 'suggests' => [], 18 | ], 19 | ]; 20 | -------------------------------------------------------------------------------- /Configuration/Backend/Modules.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'parent' => 'web', 10 | 'position' => ['after' => 'web_info'], 11 | 'access' => 'user', 12 | 'workspaces' => 'live', 13 | 'standalone' => true, 14 | 'iconIdentifier' => 'cf_cookiemanager-plugin-cookiefrontend', 15 | 'path' => '/module/web/CfCookiemanagerCookiesettings', 16 | 'labels' => 'LLL:EXT:cf_cookiemanager/Resources/Private/Language/locallang_cookiesettings.xlf', 17 | 'extensionName' => 'CfCookiemanager', 18 | 'controllerActions' => [ 19 | CodingFreaks\CfCookiemanager\Controller\CookieSettingsBackendController::class => [ 20 | 'index', 21 | ], 22 | ], 23 | 24 | ], 25 | ]; 26 | -------------------------------------------------------------------------------- /Resources/Public/Images/edit-square-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/Public/Images/edit-square-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_cookieservice.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/darkmode.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-bg: #181b1d; 3 | --cc-text: #d8e5ea; 4 | --cc-btn-primary-bg: #a6c4dd; 5 | --cc-btn-primary-text: #000; 6 | --cc-btn-primary-hover-bg: #c2dff7; 7 | --cc-btn-secondary-bg: #33383c; 8 | --cc-btn-secondary-text: var(--cc-text); 9 | --cc-btn-secondary-hover-bg: #3e454a; 10 | --cc-toggle-bg-off: #667481; 11 | --cc-toggle-bg-on: var(--cc-btn-primary-bg); 12 | --cc-toggle-bg-readonly: #454c54; 13 | --cc-toggle-knob-bg: var(--cc-cookie-category-block-bg); 14 | --cc-toggle-knob-icon-color: var(--cc-bg); 15 | --cc-block-text: #b3bfc5; 16 | --cc-cookie-category-block-bg: #23272a; 17 | --cc-cookie-category-block-bg-hover: #2b3035; 18 | --cc-section-border: #292d31; 19 | --cc-cookie-table-border: #2b3035; 20 | --cc-webkit-scrollbar-bg: #667481; 21 | --cc-webkit-scrollbar-bg-hover: #9199a0 ; 22 | } 23 | 24 | /*# sourceMappingURL=darkmode.css.map */ 25 | -------------------------------------------------------------------------------- /Classes/Updates/PluginListToCTypeUpdateWizard.php: -------------------------------------------------------------------------------- 1 | 'cfcookiemanager_cookielist', 27 | ]; 28 | } 29 | } -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_scans.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tests/Acceptance/Support/BackendTester.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {frontendSettings.customButtonHtml} 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_cookiecartegories.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/Public/Backend/Css/BackendModal.css: -------------------------------------------------------------------------------- 1 | .cf-cookiemanager-changes-modal-listitem { 2 | background: #d2d2d2; 3 | margin-bottom: 20px; 4 | padding: 20px; 5 | } 6 | [data-color-scheme=dark] .cf-cookiemanager-changes-modal-listitem { 7 | background: #4D4D4D; 8 | } 9 | @media (prefers-color-scheme: dark) { 10 | [data-color-scheme=auto] .cf-cookiemanager-changes-modal-listitem { 11 | background: #4D4D4D; 12 | } 13 | [data-theme=auto] .cf-cookiemanager-changes-modal-listitem { 14 | background: #4D4D4D; 15 | } 16 | } 17 | .cf-cookiemanager-changes-modal-listitem strong { 18 | font-size: 20px; 19 | } 20 | .cf-cookiemanager-changes-modal-listitem .cf-cookiemanager-changes-modal-changes-api, .cf-cookiemanager-changes-modal-listitem .cf-cookiemanager-changes-modal-changes-local { 21 | display: flex; 22 | font-weight: bold; 23 | font-size: 14px; 24 | } 25 | .cf-cookiemanager-changes-modal-listitem .cf-cookiemanager-changes-modal-changes-api > div, .cf-cookiemanager-changes-modal-listitem .cf-cookiemanager-changes-modal-changes-local > div { 26 | margin-left: 10px; 27 | font-weight: normal; 28 | } 29 | 30 | /*# sourceMappingURL=BackendModal.css.map */ 31 | -------------------------------------------------------------------------------- /Build/phpunit/FunctionalTestsBootstrap.php: -------------------------------------------------------------------------------- 1 | defineOriginalRootPath(); 28 | $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests'); 29 | $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient'); 30 | })(); -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/funkylight.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-bg: #f9faff; 3 | --cc-text: #112954; 4 | --cc-btn-primary-bg: #3859d0; 5 | --cc-btn-primary-text: var(--cc-bg); 6 | --cc-btn-primary-hover-bg: #1d2e38; 7 | --cc-btn-secondary-bg: #dfe7f9; 8 | --cc-btn-secondary-text: var(--cc-text); 9 | --cc-btn-secondary-hover-bg: #c6d1ea; 10 | --cc-toggle-bg-off: #8fa8d6; 11 | --cc-toggle-bg-on: #3859d0; 12 | --cc-toggle-bg-readonly: #cbd8f1; 13 | --cc-toggle-knob-bg: #fff; 14 | --cc-toggle-knob-icon-color: #ecf2fa; 15 | --cc-block-text: var(--cc-text); 16 | --cc-cookie-category-block-bg: #ebeff9; 17 | --cc-cookie-category-block-bg-hover: #dbe5f9; 18 | --cc-section-border: #f1f3f5; 19 | --cc-cookie-table-border: #e1e7f3; 20 | --cc-overlay-bg: rgba(230, 235, 255, .85); 21 | --cc-webkit-scrollbar-bg: #ebeff9; 22 | --cc-webkit-scrollbar-bg-hover: #3859d0; 23 | } 24 | 25 | .theme_funky #c-ttl{ 26 | color: var(--cc-btn-primary-bg); 27 | } 28 | 29 | /* Custom border radius */ 30 | .theme_funky #cm, 31 | .theme_funky #s-bl .act .b-acc, 32 | .theme_funky #s-inr, 33 | .theme_funky .cc_div .b-tl, 34 | .theme_funky .cc_div .c-bl{ 35 | border-radius: 1.2em; 36 | } 37 | 38 | .theme_funky .cc_div .c-bn{ 39 | border-radius: .7em; 40 | } -------------------------------------------------------------------------------- /Resources/Static/settingsmodal.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Classes/Domain/Repository/VariablesRepository.php: -------------------------------------------------------------------------------- 1 | replace($variable->getIdentifier(), $variable->getValue(), $content); 41 | } 42 | return $content; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/funkylight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-bg: #f9faff; 3 | --cc-text: #112954; 4 | --cc-btn-primary-bg: #3859d0; 5 | --cc-btn-primary-text: var(--cc-bg); 6 | --cc-btn-primary-hover-bg: #1d2e38; 7 | --cc-btn-secondary-bg: #dfe7f9; 8 | --cc-btn-secondary-text: var(--cc-text); 9 | --cc-btn-secondary-hover-bg: #c6d1ea; 10 | --cc-toggle-bg-off: #8fa8d6; 11 | --cc-toggle-bg-on: #3859d0; 12 | --cc-toggle-bg-readonly: #cbd8f1; 13 | --cc-toggle-knob-bg: #fff; 14 | --cc-toggle-knob-icon-color: #ecf2fa; 15 | --cc-block-text: var(--cc-text); 16 | --cc-cookie-category-block-bg: #ebeff9; 17 | --cc-cookie-category-block-bg-hover: #dbe5f9; 18 | --cc-section-border: #f1f3f5; 19 | --cc-cookie-table-border: #e1e7f3; 20 | --cc-overlay-bg: rgba(230, 235, 255, .85); 21 | --cc-webkit-scrollbar-bg: #ebeff9; 22 | --cc-webkit-scrollbar-bg-hover: #3859d0; 23 | } 24 | 25 | .theme_funky #c-ttl { 26 | color: var(--cc-btn-primary-bg); 27 | } 28 | 29 | /* Custom border radius */ 30 | .theme_funky #cm, 31 | .theme_funky #s-bl .act .b-acc, 32 | .theme_funky #s-inr, 33 | .theme_funky .cc_div .b-tl, 34 | .theme_funky .cc_div .c-bl { 35 | border-radius: 1.2em; 36 | } 37 | 38 | .theme_funky .cc_div .c-bn { 39 | border-radius: 0.7em; 40 | } 41 | 42 | /*# sourceMappingURL=funkylight.css.map */ 43 | -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-cookie-category-block-bg: #fff; 3 | --cc-cookie-category-block-bg-hover: #eeeeee; 4 | --cc-cookie-category-block-bordercolor: lightgrey; 5 | } 6 | 7 | /* Consent Modal */ 8 | #cm #c-inr { 9 | display: flex; 10 | flex-direction: column; 11 | } 12 | #cm #c-inr #c-bns { 13 | display: flex; 14 | flex-direction: row-reverse; 15 | } 16 | #cm #c-inr #c-bns .c-bn { 17 | margin: 0; 18 | margin-right: 20px; 19 | } 20 | #cm #c-inr #c-bns .c-bn:first-child { 21 | margin: 0; 22 | } 23 | 24 | /* Settings Modal */ 25 | #s-cnt .cfwrapper { 26 | background-color: var(--cc-cookie-category-block-bg); 27 | border: solid 1px var(--cc-cookie-category-block-bordercolor); 28 | border-radius: 5px; 29 | } 30 | #s-cnt .cfwrapper .c-bl { 31 | padding: 0 20px 0 20px; 32 | } 33 | #s-cnt .cfwrapper .c-bl .title { 34 | border-radius: 0; 35 | /* padding: 9px; */ 36 | border-bottom: solid 1px var(--cc-cookie-category-block-bordercolor); 37 | box-sizing: border-box; 38 | } 39 | #s-cnt .cfwrapper .block-section .b-ex .desc { 40 | margin-left: 0; 41 | } 42 | #s-cnt .cfwrapper .block-section .b-bn .b-tl { 43 | padding: 0.4em 6em 0.4em 1.7em; 44 | } 45 | #s-cnt .cfwrapper .block-section .b-bn .b-tl:before { 46 | left: 0.5em; 47 | } 48 | 49 | /*# sourceMappingURL=clean.css.map */ 50 | -------------------------------------------------------------------------------- /.github/workflows/core13.yml: -------------------------------------------------------------------------------- 1 | name: core 13 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | tests: 7 | name: v13 8 | runs-on: ubuntu-22.04 9 | strategy: 10 | # This prevents cancellation of matrix job runs, if one/two already failed and let the 11 | # rest matrix jobs be executed anyway. 12 | fail-fast: false 13 | matrix: 14 | php: [ '8.3', '8.4' ] 15 | composerInstall: [ 'composerInstallHighest' ] 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | 20 | - name: Install Docker Compose 21 | run: | 22 | sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 23 | sudo chmod +x /usr/local/bin/docker-compose 24 | 25 | - name: Validate composer.json and composer.lock 26 | run: Build/Scripts/runTests.sh -t 13 -p ${{ matrix.php }} -s composer -e 'validate' 27 | 28 | - name: Install testing system 29 | run: Build/Scripts/runTests.sh -t 13 -p ${{ matrix.php }} -s ${{ matrix.composerInstall }} 30 | 31 | - name: Functional Tests 32 | run: Build/Scripts/runTests.sh -t 13 -p ${{ matrix.php }} -s functional 33 | 34 | - name: Unit Tests 35 | run: Build/Scripts/runTests.sh -t 13 -p ${{ matrix.php }} -s unit -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_externalscripts.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/core14.yml: -------------------------------------------------------------------------------- 1 | name: core 14 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | tests: 7 | name: v12 8 | runs-on: ubuntu-22.04 9 | strategy: 10 | # This prevents cancellation of matrix job runs, if one/two already failed and let the 11 | # rest matrix jobs be executed anyway. 12 | fail-fast: false 13 | matrix: 14 | php: [ '8.3', '8.4' ] 15 | composerInstall: [ 'composerInstallHighest' ] # //maybe also Support composerInstallLowest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | 20 | - name: Install Docker Compose 21 | run: | 22 | sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 23 | sudo chmod +x /usr/local/bin/docker-compose 24 | 25 | - name: Install testing system 26 | run: Build/Scripts/runTests.sh -t 14 -p ${{ matrix.php }} -s ${{ matrix.composerInstall }} 27 | 28 | - name: Functional Tests 29 | run: Build/Scripts/runTests.sh -t 14 -p ${{ matrix.php }} -s functional 30 | 31 | - name: Unit Tests 32 | run: Build/Scripts/runTests.sh -t 14 -p ${{ matrix.php }} -s unit 33 | 34 | # TODO Refactor to 13 Core tests using apache2 instead of php -S 35 | #- name: Backend Functional Demo Tests 36 | # run: Build/Scripts/runTests.sh -t 12 -p ${{ matrix.php }} -s acceptance -------------------------------------------------------------------------------- /Documentation/Developer/ExtensionDevelopment/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | =========================== 5 | Environment Tools 6 | =========================== 7 | 8 | 9 | Examples of runTests.sh 10 | ---------- 11 | 12 | .. code-block:: raw 13 | 14 | - Install a TYPO3 11 with PHP 7.4: 15 | ./Build/Scripts/runTests.sh -s composerInstall -p 7.4 -t 11 16 | 17 | 18 | - Install a TYPO3 12 with PHP 8.1: 19 | ./Build/Scripts/runTests.sh -s composerInstall -p 8.1 -t 12 20 | 21 | 22 | - Unit-Tests with PHP 7.4: 23 | ./Build/Scripts/runTests.sh -s unit 24 | 25 | 26 | - Functional-Tests with PHP 8.1: 27 | ./Build/Scripts/runTests.sh -s unit -p 8.1 28 | 29 | 30 | - Run acceptance Tests with PHP 8.1 for TYPO3 12: 31 | ./Build/Scripts/runTests.sh -s acceptance -p 8.1 -t 12 32 | 33 | 34 | 35 | Development Environment 36 | ----------------------- 37 | 38 | You can use the Acceptance Tests docker-compose file to setup a development environment for quick testing. 39 | 40 | ``cd Build/testing-docker`` folder and run: ``docker-compose run acceptance_test`` 41 | This Launches a container with your runTests.sh install parameters and Setup a basic Frontend and Backend. 42 | 43 | Add the following to your ``/etc/hosts`` file: ``127.0.0.1 web`` 44 | 45 | - Login to the Backend: http://web/typo3temp/var/tests/acceptance/typo3 46 | - Credentials are: ``admin`` / ``password`` 47 | 48 | Frontend is available at: http://web/typo3temp/var/tests/acceptance/ 49 | 50 | -------------------------------------------------------------------------------- /Resources/Public/Scss/theme/clean.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --cc-cookie-category-block-bg: #fff; 3 | --cc-cookie-category-block-bg-hover: #eeeeee; 4 | --cc-cookie-category-block-bordercolor: lightgrey; 5 | } 6 | 7 | /* Consent Modal */ 8 | #cm { 9 | #c-inr { 10 | display: flex; 11 | flex-direction: column; 12 | 13 | #c-bns { 14 | display: flex; 15 | flex-direction: row-reverse; 16 | 17 | .c-bn { 18 | margin: 0; 19 | margin-right: 20px; 20 | 21 | &:first-child { 22 | margin: 0; 23 | } 24 | } 25 | } 26 | } 27 | } 28 | 29 | /* Settings Modal */ 30 | #s-cnt { 31 | .cfwrapper { 32 | background-color: var(--cc-cookie-category-block-bg); 33 | border: solid 1px var(--cc-cookie-category-block-bordercolor); 34 | border-radius: 5px; 35 | 36 | .c-bl { 37 | padding: 0 20px 0 20px; 38 | 39 | .title { 40 | // border-top: solid 1px var(--cc-cookie-category-block-bordercolor); 41 | border-radius: 0; 42 | /* padding: 9px; */ 43 | border-bottom: solid 1px var(--cc-cookie-category-block-bordercolor); 44 | box-sizing: border-box; 45 | } 46 | } 47 | 48 | .block-section { 49 | .b-ex .desc { 50 | margin-left: 0; 51 | } 52 | 53 | .b-bn { 54 | .b-tl { 55 | padding: 0.4em 6em 0.4em 1.7em; 56 | 57 | &:before { 58 | left: 0.5em; 59 | } 60 | } 61 | 62 | } 63 | } 64 | 65 | } 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /Documentation/Introduction/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | .. _introduction: 4 | 5 | ============ 6 | Introduction 7 | ============ 8 | 9 | An awesome simple cookie Manager for your Typo3 installation, with service and script management! 10 | 11 | Key features 12 | ================ 13 | * Script Blocker / Script Management 14 | * Lazy Load Iframes and Divs for Thirdparty Content 15 | * Easy custom Implementation 16 | * Standalone (no external dependencies needed) 17 | * GDPR compliant 18 | * Support for multi language (Currently 9 Languages Preconfigured per API) 19 | * WAI-ARIA compliant 20 | * Allows you to define different cookie categories with opt in/out toggle 21 | * Allows you to define custom cookie tables to specify the cookies you use 22 | * Dark and Lightmode Support in the Typo3 v13 Backend 23 | 24 | This plugin provides a solution for the EU Cookie law (ePrivacy, TTDSG). It allows loading of scripts, iframes, and content only after the user has given their consent. 25 | However, you don't need to worry about the latest EU laws as this plugin manages your cookies. 26 | 27 | .. youtube:: z-jsd9w4Dmg 28 | 29 | 30 | Demo 31 | ---------- 32 | 33 | :ref:`Cookie-Manager, Frontend Demo: https://cookiedemo.coding-freaks.com/` 34 | 35 | 36 | .. _screenshots: 37 | 38 | Screenshots 39 | =========== 40 | 41 | Frontend Preview of the Consent Manager 42 | 43 | .. figure:: ../Images/cookie_settings.png 44 | :class: with-shadow 45 | :alt: Introduction Package 46 | :width: 100% 47 | 48 | Settings Modal. 49 | -------------------------------------------------------------------------------- /Configuration/Backend/DashboardWidgets.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | _defaults: 3 | autowire: true 4 | autoconfigure: true 5 | public: false 6 | 7 | CodingFreaks\CfCookiemanager\: 8 | resource: '../Classes/*' 9 | 10 | dashboard.widget.consentTrackingDonutAcceptTypes: 11 | class: 'TYPO3\CMS\Dashboard\Widgets\DoughnutChartWidget' 12 | arguments: 13 | $dataProvider: '@CodingFreaks\CfCookiemanager\Widgets\Provider\ConsentTrackingDonutAcceptTypes' 14 | tags: 15 | - name: dashboard.widget 16 | identifier: 'consentTrackingDonutAcceptTypes' 17 | groupNames: 'general' 18 | title: 'Consent Tracking, accept types' 19 | description: 'Shows the amount of users who accepted the cookie types (necessary, custom, all)' 20 | iconIdentifier: 'content-widget-chart-pie' 21 | height: 'medium' 22 | 23 | dashboard.widget.consentTracking: 24 | class: 'TYPO3\CMS\Dashboard\Widgets\BarChartWidget' 25 | arguments: 26 | $dataProvider: '@CodingFreaks\CfCookiemanager\Widgets\Provider\ConsentTrackingDataProvider' 27 | #$buttonProvider: '@CCodingFreaks\CfCookiemanager\Widgets\Provider\ConsentTrackingButtonProvider' 28 | $options: 29 | refreshAvailable: true 30 | tags: 31 | - name: dashboard.widget 32 | identifier: 'consentTracking' 33 | groupNames: 'general' 34 | title: 'Cookie Consent Tracking' 35 | description: 'Optin/Optout Tracking' 36 | iconIdentifier: 'content-widget-chart-bar' 37 | height: 'medium' 38 | width: 'medium' -------------------------------------------------------------------------------- /Classes/Event/ClassifyContentEvent.php: -------------------------------------------------------------------------------- 1 | providerURL = $providerURL; 26 | } 27 | /** 28 | 29 | Get the provider URL. 30 | @return string The URL of the content provider 31 | */ 32 | public function getProviderURL(): string 33 | { 34 | return $this->providerURL; 35 | } 36 | /** 37 | 38 | Set the service identifier. 39 | @param string $serviceIdentifier The identifier of the service 40 | */ 41 | public function setServiceIdentifier(string $serviceIdentifier): void 42 | { 43 | $this->serviceIdentifier = $serviceIdentifier; 44 | } 45 | /** 46 | 47 | Get the service identifier. 48 | @return string|null The identifier of the service, or null if not set 49 | */ 50 | public function getServiceIdentifier(): ?string 51 | { 52 | return $this->serviceIdentifier; 53 | } 54 | } -------------------------------------------------------------------------------- /Documentation/Configuration/Index.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | .. include:: ../Includes.txt 5 | 6 | .. _configuration: 7 | 8 | ============= 9 | Configuration 10 | ============= 11 | 12 | In general, it is easiest to edit the extension in the backend in the :guilabel:`Cookie Settings` module. 13 | 14 | What you should also consider is that you create the settings for the cookie categories and services in the respective language. This means that if you have a multilingual website, you must create the settings for each language. 15 | 16 | .. figure:: ../Images/Configuration/backend_after_first_install.png 17 | :class: with-shadow 18 | :alt: Backend 19 | :width: 100% 20 | 21 | 22 | Tracking 23 | -------- 24 | 25 | If you want to know how many outouts/optins the Cookie Consent has, you can enable the tracking. 26 | 27 | This can be done by enabling the tracking in the :guilabel:`Extension Configuration` in the settings module from typo3, by clicking `Enable Cookie Consent Tracking`. 28 | 29 | If active the first Action of the Visitor, in the Consent Modal is tracked before any external Javascript is loaded. 30 | 31 | The tracking is done by a simple Ajax call to the backend controller, and dose not store any personal data. 32 | 33 | You can see the statistics by using the Typo3 Dashboard Module and add the Cookie Consent Widget to the Dashboard. 34 | 35 | 36 | 37 | 38 | Table of contents. 39 | ================= 40 | 41 | .. toctree:: 42 | :maxdepth: 5 43 | :titlesonly: 44 | 45 | AutoConfiguration/Index 46 | CookieCategories/Index 47 | CookieServices/Index 48 | ExtensionSettings/Index 49 | FrontendSettings/Index 50 | -------------------------------------------------------------------------------- /Configuration/Backend/AjaxRoutes.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'path' => '/cf-cookiemanager/ajax/check-for-database-updates', 8 | 'target' => BackendAjax\UpdateCheckController::class . '::checkForUpdatesAction', 9 | ], 10 | 11 | 'cfcookiemanager_ajax_updatedataset' => [ 12 | 'path' => '/cf-cookiemanager/ajax/update-dataset', 13 | 'target' => BackendAjax\UpdateCheckController::class . '::updateDatasetAction', 14 | ], 15 | 16 | 'cfcookiemanager_ajax_insertdataset' => [ 17 | 'path' => '/cf-cookiemanager/ajax/insert-dataset', 18 | 'target' => BackendAjax\UpdateCheckController::class . '::insertDatasetAction', 19 | ], 20 | 21 | 'cfcookiemanager_ajax_installdatasets' => [ 22 | 'path' => '/cf-cookiemanager/ajax/install-datasets', 23 | 'target' => BackendAjax\InstallController::class . '::installDatasetsAction', 24 | ], 25 | 26 | 'cfcookiemanager_ajax_uploaddataset' => [ 27 | 'path' => '/cf-cookiemanager/ajax/upload-datasets', 28 | 'target' => BackendAjax\InstallController::class . '::uploadDatasetAction', 29 | ], 30 | 31 | 'cfcookiemanager_ajax_checkapidata' => [ 32 | 'path' => '/cf-cookiemanager/ajax/check-api-data', 33 | 'target' => BackendAjax\InstallController::class . '::checkApiDataAction', 34 | ], 35 | 36 | 'cfcookiemanager_ajax_clearthumbnailcache' => [ 37 | 'path' => '/cf-cookiemanager/ajax/clear-thumbnail-cache', 38 | 'target' => BackendAjax\ThumbnailController::class . '::clearThumbnailCache', 39 | ], 40 | ]; -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_cfcookiemanager_domain_model_cookie.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/Public/JavaScript/TutorialTours/TourManager.js: -------------------------------------------------------------------------------- 1 | import $ from "jquery"; 2 | import Tour from '@codingfreaks/cf-cookiemanager/thirdparty/bootstrap-tour.js'; 3 | import DocumentService from '@typo3/core/document-service.js'; 4 | 5 | async function loadTour(tourName) { 6 | const tourModule = await import(`@codingfreaks/cf-cookiemanager/TutorialTours/${tourName}.js`); 7 | return new Tour(tourModule.default); 8 | } 9 | 10 | DocumentService.ready().then(async () => { 11 | let tourMap = {}; 12 | 13 | $(".startTour").click(async function (e) { 14 | let selectedTourName = $(this).data("tour"); 15 | if (!tourMap[selectedTourName]) { 16 | tourMap[selectedTourName] = { run: await loadTour(selectedTourName) }; 17 | } 18 | tourMap[selectedTourName].run.init(); 19 | tourMap[selectedTourName].run.restart(); 20 | }); 21 | 22 | if (typeof sessionStorage.getItem("currentTour") !== "undefined" && sessionStorage.getItem("currentTour") !== null && sessionStorage.getItem("currentTour") !== "") { 23 | let currentTour = sessionStorage.getItem("currentTour"); 24 | setTimeout(async function () { 25 | if (!tourMap[currentTour]) { 26 | tourMap[currentTour] = { run: await loadTour(currentTour) }; 27 | } 28 | tourMap[currentTour].run.init(); 29 | tourMap[currentTour].run.start(); 30 | }, 1000); 31 | } 32 | 33 | $("body").delegate(".force-end-tour","click", function (e) { 34 | let currentTour = sessionStorage.getItem("currentTour"); 35 | tourMap[currentTour].run.end(); 36 | sessionStorage.setItem("currentTour", ""); 37 | }); 38 | }); -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | jobs: 7 | publish: 8 | name: Publish new version to TER 9 | if: startsWith(github.ref, 'refs/tags/') 10 | runs-on: ubuntu-22.04 11 | env: 12 | TYPO3_EXTENSION_KEY: ${{ secrets.TYPO3_EXTENSION_KEY }} 13 | TYPO3_API_TOKEN: ${{ secrets.TYPO3_API_TOKEN }} 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v3 17 | 18 | - name: Check tag 19 | run: | 20 | if ! [[ ${{ github.ref }} =~ ^refs/tags/v[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$ ]]; then 21 | exit 1 22 | fi 23 | 24 | - name: Get version 25 | id: get-version 26 | run: echo "version=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV 27 | 28 | - name: Get comment 29 | id: get-comment 30 | run: | 31 | readonly local comment=$(git tag -n10 -l v${{ env.version }} | sed "s/^[0-9.]*[ ]*//g") 32 | 33 | if [[ -z "${comment// }" ]]; then 34 | echo "comment=Released version ${{ env.version }} of ${{ env.TYPO3_EXTENSION_KEY }}" >> $GITHUB_ENV 35 | else 36 | echo "comment=$comment" >> $GITHUB_ENV 37 | fi 38 | 39 | - name: Setup PHP 40 | uses: shivammathur/setup-php@v2 41 | with: 42 | php-version: 7.4 43 | extensions: intl, mbstring, json, zip, curl 44 | tools: composer:v2 45 | 46 | - name: Install tailor 47 | run: composer global require typo3/tailor --prefer-dist --no-progress --no-suggest 48 | 49 | - name: Publish to TER 50 | run: php ~/.composer/vendor/bin/tailor ter:publish --comment "${{ env.comment }}" ${{ env.version }} -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/tx_cfcookiemanager_domain_model_cookiecartegories.php: -------------------------------------------------------------------------------- 1 | 'input', 6 | 'size' => 30, 7 | 'eval' => 'trim', 8 | 'default' => '', 9 | "readOnly" => false, //Disabled because v12 issue missing data-formengine-input-name for autoselect Detection 10 | ]; 11 | 12 | $GLOBALS["TCA"]["tx_cfcookiemanager_domain_model_cookiecartegories"]["columns"]["cookie_services"]["config"] = [ 13 | 'type' => 'select', 14 | 'renderType' => 'CfSelectMultipleSideBySide', 15 | 'foreign_table' => 'tx_cfcookiemanager_domain_model_cookieservice', 16 | 'foreign_table_where' => 'tx_cfcookiemanager_domain_model_cookieservice.sys_language_uid = ###REC_FIELD_sys_language_uid### AND tx_cfcookiemanager_domain_model_cookieservice.pid=###CURRENT_PID### AND tx_cfcookiemanager_domain_model_cookieservice.hidden = 0', 17 | 'MM' => 'tx_cfcookiemanager_cookiecartegories_cookieservice_mm', 18 | 'size' => 10, 19 | 'autoSizeMax' => 30, 20 | 'maxitems' => 9999, 21 | 'behaviour' => [ 22 | 'allowLanguageSynchronization' => true 23 | ], 24 | 'multiple' => 0, 25 | 'itemsProcFunc' => CodingFreaks\CfCookiemanager\Utility\HelperUtility::class . '->itemsProcFunc', 26 | //'multiSelectFilterItems' => $multiSelectFilterItems, 27 | //'itemGroups' => $itemGroups, 28 | 'fieldControl' => [ 29 | 'editPopup' => [ 30 | 'disabled' => false, 31 | ], 32 | 'addRecord' => [ 33 | 'disabled' => false, 34 | ], 35 | 'listModule' => [ 36 | 'disabled' => true, 37 | ], 38 | ], 39 | ]; 40 | -------------------------------------------------------------------------------- /Resources/Public/JavaScript/Tracking.js: -------------------------------------------------------------------------------- 1 | 2 | function sendData(url,data) { 3 | const XHR = new XMLHttpRequest(); 4 | const urlEncodedDataPairs = []; 5 | // Turn the data object into an array of URL-encoded key/value pairs. 6 | for (const [name, value] of Object.entries(data)) { 7 | urlEncodedDataPairs.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`); 8 | } 9 | // Combine the pairs into a single string and replace all %-encoded spaces to 10 | // the '+' character; matches the behavior of browser form submissions. 11 | const urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+'); 12 | 13 | 14 | /* Define what happens in case of an error 15 | XHR.addEventListener('error', (event) => { 16 | callback(new Error("Request failed with status " + this.status)); 17 | }); 18 | XHR.onreadystatechange = function() { 19 | if (this.readyState === 4) { 20 | if (this.status === 200) { 21 | callback(null, this.responseText); 22 | } else { 23 | callback(new Error("Request failed with status " + this.status)); 24 | } 25 | } 26 | }; 27 | */ 28 | 29 | // Set up our request 30 | XHR.open('POST', atob(url)); 31 | // Add the required HTTP header for form data POST requests 32 | XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 33 | // Finally, send our data. 34 | XHR.send(urlEncodedData); 35 | } 36 | 37 | var url = '{{tracking_url}}'; 38 | const data = { 39 | languageCode: navigator.language, 40 | referrer: document.referrer, 41 | navigator: navigator.webdriver, 42 | consent_type: user_preferences.accept_type, 43 | }; 44 | 45 | sendData(url,data) -------------------------------------------------------------------------------- /Build/phpunit/UnitTests.xml: -------------------------------------------------------------------------------- 1 | 10 | 31 | 32 | 33 | 37 | ../../Tests/Unit 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Resources/Private/Templates/CookieFrontend/CookieList.html: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /Resources/Private/Language/da.locallang.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | Name 8 | Navn 9 | 10 | 11 | Provider 12 | Udbyder 13 | 14 | 15 | Expiry 16 | Udløbsdato 17 | 18 | 19 | Domain 20 | Domæne 21 | 22 | 23 | Path 24 | Sti 25 | 26 | 27 | Secure 28 | Kun HTTPS 29 | 30 | 31 | Description 32 | Beskrivelse 33 | 34 | 35 | Service blocked by Script-blocker 36 | Denne service blokeres af Script-blocker 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Tests/Acceptance/Support/Extension/BackendEnvironment.php: -------------------------------------------------------------------------------- 1 | [ 34 | 'core', 35 | 'dashboard', 36 | 'extbase', 37 | 'fluid', 38 | 'backend', 39 | 'install', 40 | 'frontend', 41 | 'tstemplate', 42 | 'seo', 43 | ], 44 | 'testExtensionsToLoad' => [ 45 | 'typo3conf/ext/cf_cookiemanager', 46 | ], 47 | 'csvDatabaseFixtures' => [ 48 | __DIR__ . '/../../Fixtures/BackendEnvironment.csv', 49 | ], 50 | 'pathsToLinkInTestInstance' => [ 51 | '/typo3conf/ext/cf_cookiemanager/Tests/Acceptance/Fixtures/SystemConfiguration/Sites' => '/typo3conf/sites', 52 | ] 53 | ]; 54 | 55 | 56 | } -------------------------------------------------------------------------------- /Tests/Acceptance/Backend.suite.yml: -------------------------------------------------------------------------------- 1 | actor: BackendTester 2 | 3 | step_decorators: 4 | - \Codeception\Step\ConditionalAssertion 5 | - \Codeception\Step\TryTo 6 | 7 | modules: 8 | enabled: 9 | - WebDriver: 10 | url: 'http://web/typo3temp/var/tests/acceptance/' 11 | browser: chrome 12 | wait: 2 13 | host: chrome 14 | capabilities: 15 | chromeOptions: 16 | args: ["--no-sandbox", "window-size=1280,1024", "--disable-gpu", "--unsafely-treat-insecure-origin-as-secure=http://web","--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36-CF-CookieScanner"] 17 | - \TYPO3\TestingFramework\Core\Acceptance\Helper\Acceptance 18 | - \TYPO3\TestingFramework\Core\Acceptance\Helper\Login: 19 | sessions: 20 | # These sessions must exist in the database fixture to get a logged in state. 21 | editor: ff83dfd81e20b34c27d3e97771a4525a 22 | admin: 886526ce72b86870739cc41991144ec1 23 | - Asserts 24 | - Codeception\Module\Cli 25 | 26 | env: 27 | headless: 28 | modules: 29 | enabled: 30 | - WebDriver: 31 | url: 'http://web/typo3temp/var/tests/acceptance/' 32 | browser: chrome 33 | wait: 5 34 | host: chrome 35 | capabilities: 36 | chromeOptions: 37 | args: ["--headless", "--no-sandbox", "window-size=1280,1024", "--disable-gpu","--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36-CF-CookieScanner"] 38 | 39 | extensions: 40 | enabled: 41 | - CodingFreaks\CfCookiemanager\Tests\Acceptance\Support\Extension\BackendEnvironment 42 | 43 | groups: 44 | AcceptanceTests-Job-*: AcceptanceTests-Job-* -------------------------------------------------------------------------------- /Classes/Controller/BackendAjax/ThumbnailController.php: -------------------------------------------------------------------------------- 1 | thumbnailService->clearThumbnailCache(); 32 | 33 | $response = $this->responseFactory->createResponse()->withHeader('Content-Type', 'application/json; charset=utf-8'); 34 | $response->getBody()->write(json_encode( 35 | [ 36 | 'clearSuccess' => $success, 37 | ], 38 | JSON_THROW_ON_ERROR 39 | )); 40 | return $response; 41 | } 42 | 43 | /** 44 | * Retrieves the current backend user. 45 | * 46 | * This method returns the current backend user authentication object. 47 | * It is used to get information about the logged-in backend user. 48 | * 49 | * @return BackendUserAuthentication The backend user authentication object. 50 | */ 51 | protected function getBackendUser(): BackendUserAuthentication 52 | { 53 | return $GLOBALS['BE_USER']; 54 | } 55 | } -------------------------------------------------------------------------------- /Documentation/Index.rst: -------------------------------------------------------------------------------- 1 | .. every .rst file should include Includes.txt 2 | .. use correct path! 3 | 4 | .. include:: Includes.txt 5 | 6 | .. Every manual should have a start label for cross-referencing to 7 | .. start page. Do not remove this! 8 | 9 | .. _start: 10 | 11 | ============================================================= 12 | Coding Freaks Cookie Manager 13 | ============================================================= 14 | 15 | :Version: 16 | |release| 17 | 18 | :Language: 19 | en 20 | 21 | :Authors: 22 | Florian Eibisberger 23 | 24 | :Email: 25 | 26 | :License: 27 | This extension documentation is published under the 28 | `CC BY-NC-SA 4.0 `__ (Creative Commons) 29 | license 30 | 31 | **TYPO3** 32 | 33 | The content of this document is related to TYPO3 CMS, 34 | a GNU/GPL CMS/Framework available from `typo3.org `_ . 35 | 36 | **Community Documentation** 37 | 38 | This documentation is community documentation for the TYPO3 extension Coding Freaks Cookie Manager 39 | 40 | It is maintained as part of this third party extension. 41 | 42 | If you find an error or something is missing, please: 43 | `Report a Problem `__ 44 | 45 | **Extension Manual** 46 | 47 | This documentation is for the TYPO3 extension cf_cookiemanager. 48 | 49 | **For Contributors** 50 | 51 | You are welcome to help improve this guide. 52 | Just click on "Edit me on GitHub" on the top right to submit your change request. 53 | 54 | .. youtube:: z-jsd9w4Dmg 55 | 56 | .. toctree:: 57 | :maxdepth: 3 58 | 59 | Introduction/Index 60 | Installation/Index 61 | Configuration/Index 62 | Developer/Index 63 | KnownProblems/Index 64 | ChangeLog/Index 65 | Sitemap 66 | -------------------------------------------------------------------------------- /Resources/Private/Language/locallang.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | Cookie details 8 | 9 | 10 | Name 11 | 12 | 13 | Provider 14 | 15 | 16 | Expiry 17 | 18 | 19 | Domain 20 | 21 | 22 | Path 23 | 24 | 25 | Secure 26 | 27 | 28 | Description 29 | 30 | 31 | Service blocked by Script-blocker 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Resources/Private/Partials/BackendTabs/frontend.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Frontend Configuration

6 | Static Text management, Display Options, Theme management and more.. 7 |
8 |
9 |
10 |
11 |
12 | 13 |
14 | 15 | 27 | 28 |
29 | 30 |
31 |
32 |
33 |

Frontend Settings

34 |

Cookie frontend settings are responsible for the UI texts of the cookie box.

35 | 38 |
39 |
40 |
41 |
-------------------------------------------------------------------------------- /Resources/Public/JavaScript/Backend/initCookieBackend.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | //import jqueryDatatable from 'jquery-datatable'; 3 | 4 | $(".settings-item-head").click(function(){ 5 | let category = $(this).parent().data("category"); 6 | $(this).parent().find(".setting-item-row").toggle(); 7 | $(this).toggleClass("settings-item-head-line"); 8 | 9 | // Retrieve the current status object from session storage or create a new one if it doesn't exist 10 | var categoryStatus = JSON.parse(sessionStorage.getItem("categoryStatus")) || {}; 11 | categoryStatus[category] = $(this).parent().find(".setting-item-row").css("display"); 12 | sessionStorage.setItem("categoryStatus", JSON.stringify(categoryStatus)); 13 | 14 | // sessionStorage.setItem("cf_"+currentCat, $(this).parent().find(".setting-item-row").css("display") !== "none"); 15 | }); 16 | 17 | if (sessionStorage.getItem("cf_current_tab")) { 18 | $(".cf_manager .active").removeClass("active"); 19 | $("[aria-controls=" + sessionStorage.getItem("cf_current_tab") + "]").addClass("active"); 20 | $("#" + sessionStorage.getItem("cf_current_tab")).addClass("active"); 21 | } 22 | 23 | $(".cf_manager .t3js-tabmenu-item").click(function () { 24 | sessionStorage.setItem("cf_current_tab", $(this).find("a").attr("aria-controls")); 25 | }); 26 | 27 | 28 | var categoryStatus = JSON.parse(sessionStorage.getItem("categoryStatus")) || {}; 29 | // Loop through each category in Home tab and show or hide the corresponding div based on its status 30 | for (var category in categoryStatus) { 31 | if (categoryStatus.hasOwnProperty(category)) { 32 | var divToToggle = $('[data-category=\"' + category + '\"]'); 33 | if(categoryStatus[category] === "block"){ 34 | divToToggle.find(".settings-item-head").addClass("settings-item-head-line"); 35 | } 36 | divToToggle.find(".setting-item-row").css("display",categoryStatus[category]); 37 | } 38 | } 39 | 40 | 41 | $(".loadingcontainer").hide(); 42 | $(".cf_manager").show(); 43 | 44 | export default {cookieBackendLoaded: 1}; -------------------------------------------------------------------------------- /Configuration/Services.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: Backend/DashboardWidgets.yaml } 3 | services: 4 | # general settings 5 | _defaults: 6 | autowire: true 7 | autoconfigure: true 8 | public: false 9 | 10 | CodingFreaks\CfCookiemanager\: 11 | resource: '../Classes/*' 12 | 13 | # dependency injection (override public setting) 14 | CodingFreaks\CfCookiemanager\Controller\CookieSettingsBackendController: 15 | public: true 16 | tags: [ 'backend.controller' ] 17 | 18 | CodingFreaks\CfCookiemanager\Service\AutoconfigurationService: 19 | public: true 20 | 21 | CodingFreaks\CfCookiemanager\Service\ThumbnailService: 22 | public: true 23 | 24 | CodingFreaks\CfCookiemanager\Utility\RenderUtility: 25 | autowire: true 26 | public: true 27 | arguments: 28 | $eventDispatcher: '@Psr\EventDispatcher\EventDispatcherInterface' 29 | 30 | CodingFreaks\CfCookiemanager\EventListener\AddIntroJsModule: 31 | tags: 32 | - name: event.listener 33 | event: TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent 34 | 35 | CodingFreaks\CfCookiemanager\Controller\BackendAjax\UpdateCheckController: 36 | public: true 37 | arguments: 38 | $responseFactory: '@Psr\Http\Message\ResponseFactoryInterface' 39 | 40 | CodingFreaks\CfCookiemanager\Controller\BackendAjax\InstallController: 41 | public: true 42 | 43 | CodingFreaks\CfCookiemanager\Hooks\DataHandlerHook: 44 | public: true 45 | 46 | CodingFreaks\CfCookiemanager\Controller\BackendAjax\ThumbnailController: 47 | public: true 48 | 49 | CodingFreaks\CfCookiemanager\Updates\FrontendIdentifierUpdateWizard: 50 | class: CodingFreaks\CfCookiemanager\Updates\FrontendIdentifierUpdateWizard 51 | autowire: true 52 | public: true 53 | tags: 54 | - name: typo3.install.updatewizard 55 | 56 | CodingFreaks\CfCookiemanager\Updates\PluginListToCTypeUpdateWizard: 57 | class: CodingFreaks\CfCookiemanager\Updates\PluginListToCTypeUpdateWizard 58 | autowire: true 59 | public: true 60 | tags: 61 | - name: typo3.install.updatewizard -------------------------------------------------------------------------------- /Resources/Private/Partials/BackendTabs/categories.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 |

Category Configuration

7 | Groups for the Cookie services 8 |
9 |
10 |
11 |
12 |
13 |
14 | 24 | 25 |
26 |
27 |
28 |
29 | Create new Category 30 |
31 |
32 |

Category Configuration

33 |

Cookie Category are responsible for the Group management of the Settings Modal.

34 | 37 |
38 |
39 |
40 |
-------------------------------------------------------------------------------- /Resources/Private/Partials/BackendTabs/administration.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 |

Extension Administration

7 | Deep dive into Coding-Freaks CookieManager Datasets 8 |
9 |
10 |
11 |
12 |
13 |
14 | 17 |

Check your Services with the latest Presets on coding-freaks.com

18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 | 29 |

Clear iFrame Thumbnail data, generated by coding-freaks Thumbnail API

30 | 31 |
32 | 33 |
34 |
35 |
36 |

Data Administration

37 |

38 | Complete Integration for the Coding-Freaks API. 39 |

40 |
41 |
42 |
43 |
-------------------------------------------------------------------------------- /Resources/Public/JavaScript/Backend/BackendAjax/ThumbnailService.js: -------------------------------------------------------------------------------- 1 | import AjaxRequest from "@typo3/core/ajax/ajax-request.js"; 2 | import RegularEvent from '@typo3/core/event/regular-event.js'; 3 | import Modal from '@typo3/backend/modal.js'; 4 | import Severity from "@typo3/backend/severity.js"; 5 | 6 | new RegularEvent('click', function() { 7 | const spinner = document.getElementById('loading-spinner-thumbnail-cache'); 8 | spinner.style.display = 'block'; 9 | 10 | new AjaxRequest(TYPO3.settings.ajaxUrls.cfcookiemanager_clearthumbnailcache) 11 | .post({}) 12 | .then(async function(response) { 13 | const result = await response.resolve(); 14 | 15 | 16 | if(result.clearSuccess === false) { 17 | Modal.advanced({ 18 | content: 'Error clearing thumbnail cache Request, maybe the cache is already empty or the cache folder is not writable.', 19 | severity: Severity.error, 20 | title: 'Error' 21 | }); 22 | return; 23 | } 24 | 25 | Modal.advanced({ 26 | content: 'Thumbnail cache cleared successfully.', 27 | severity: Severity.info, 28 | title: 'Success', 29 | buttons: [{ 30 | btnClass: "btn-success", 31 | name: "dismiss", 32 | icon: "actions-close", 33 | text: "Close", 34 | trigger: function(event, modal) { 35 | modal.hideModal(); 36 | location.reload(); 37 | } 38 | }] 39 | }); 40 | }) 41 | .catch(function(error) { 42 | Modal.advanced({ 43 | content: 'Error clearing thumbnail cache Request, check your logs.', 44 | severity: Severity.error, 45 | title: 'Error' 46 | }); 47 | }) 48 | .finally(function() { 49 | spinner.style.display = 'none'; 50 | }); 51 | }).bindTo(document.getElementById('cf-clear-thumbnail-cache')); -------------------------------------------------------------------------------- /Documentation/Configuration/FrontendSettings/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | ============= 5 | Cookie Frontend Settings 6 | ============= 7 | 8 | In the "Cookie Frontend Settings" tab, settings for the frontend are stored. 9 | 10 | For example: :guilabel:`Frontend Consent Modal, Frontend Settings Modal, Frontend Iframe Managers`. 11 | 12 | 13 | .. _configuration-consent-modal: 14 | 15 | 16 | Frontend Consent Modal: 17 | ====================== 18 | 19 | From here, you can make advanced settings for the Consent Modal. UI Position, Button Logics, and more. 20 | 21 | The layout of the box can be influenced through :guilabel:`layout_consent_modal,transition_consent_modal,position_consent_modal` in the backend. 22 | 23 | 24 | .. figure:: ../../Images/Ui/backend_consentmodal.png 25 | :class: with-shadow 26 | :alt: Backend Consentmodal 27 | :width: 100% 28 | 29 | 30 | 31 | 32 | Default Frontend Preview: 33 | --------------------- 34 | 35 | 36 | .. figure:: ../../Images/Ui/frontend_consentmodal.png 37 | :class: with-shadow 38 | :alt: Frontend Consentmodal 39 | :width: 300px 40 | 41 | 42 | 43 | 44 | .. _configuration-settings-modal: 45 | 46 | Frontend Settings Modal 47 | --------------------- 48 | 49 | The settings modal is the detailed view of individual services and cookie groups. 50 | 51 | Here, static texts can be replaced. 52 | 53 | .. figure:: ../../Images/Ui/backend_settingsmodal.png 54 | :class: with-shadow 55 | :alt: Frontend Settingsmodal 56 | :width: 100% 57 | 58 | .. figure:: ../../Images/cookie_settings.png 59 | :class: with-shadow 60 | :alt: Introduction Package 61 | :width: 100% 62 | 63 | 64 | Customize Frontend Section 65 | --------------------- 66 | 67 | The cookie manager offers a field in the frontend settings to override the consent button. 68 | 69 | Here, HTML can be inserted to replace the static button, which can then be styled dynamically. 70 | 71 | Additionally, there is an option to run the frontend javascript as inline javascript. 72 | 73 | This can be changed as desired with :guilabel:`in_line_execution` checkbox. 74 | 75 | If you want to override the Consent Template you can set your paths in extension settings of typo3. -------------------------------------------------------------------------------- /Resources/Private/Partials/BackendTabs/services.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 |
7 |
8 |

Service Configuration

9 | Static Scripts and Text management, Iframe embeds and more.. 10 |
11 |
12 |
13 |
14 |
15 |
16 | 28 |
29 |
30 |
31 |
32 | Create new Service 33 |
34 |
35 |

Service Configuration

36 |

Cookie services responsible for the Iframe and Script management of the website.

37 | 40 |
41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /Resources/Private/Language/de.locallang.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | Cookie details 8 | Cookie-Details 9 | 10 | 11 | Name 12 | Name 13 | 14 | 15 | Provider 16 | Provider 17 | 18 | 19 | Expiry 20 | Ablaufdatum 21 | 22 | 23 | Domain 24 | Domain 25 | 26 | 27 | Path 28 | Speicher-Ort 29 | 30 | 31 | Only Https 32 | Nur Https 33 | 34 | 35 | Description 36 | Beschreibung 37 | 38 | 39 | Service blocked by Script-blocker 40 | Dieser Service wurde von dem Scriptblocker blockiert 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Resources/Public/JavaScript/FormEngine/Element/CfSelectMultipleSideBySideElement.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the TYPO3 CMS project. 3 | * 4 | * It is free software; you can redistribute it and/or modify it under 5 | * the terms of the GNU General Public License, either version 2 6 | * of the License, or any later version. 7 | * 8 | * For the full copyright and license information, please read the 9 | * LICENSE.txt file that was distributed with this source code. 10 | * 11 | * The TYPO3 project - inspiring people to share! 12 | */ 13 | import {AbstractSortableSelectItems} from "@typo3/backend/form-engine/element/abstract-sortable-select-items.js"; 14 | import DocumentService from "@typo3/core/document-service.js"; 15 | import FormEngine from "@typo3/backend/form-engine.js"; 16 | import SelectBoxFilter from "@codingfreaks/cf-cookiemanager/FormEngine/Element/Extra/SelectBoxFilter.js"; 17 | import RegularEvent from "@typo3/core/event/regular-event.js"; 18 | 19 | export default class SelectMultipleSideBySideElement extends AbstractSortableSelectItems { 20 | constructor(e, t) { 21 | super(); 22 | this.selectedOptionsElement = null; 23 | this.availableOptionsElement = null; 24 | DocumentService.ready().then(l => { 25 | this.selectedOptionsElement = l.getElementById(e); 26 | this.availableOptionsElement = l.getElementById(t); 27 | this.registerEventHandler(); 28 | }); 29 | } 30 | 31 | registerEventHandler() { 32 | this.registerSortableEventHandler(this.selectedOptionsElement); 33 | this.availableOptionsElement.addEventListener("click", e => { 34 | const t = e.currentTarget; 35 | const l = t.dataset.relatedfieldname; 36 | if (l) { 37 | const e = t.dataset.exclusivevalues; 38 | const n = t.querySelectorAll("option:checked"); 39 | if (n.length > 0) { 40 | n.forEach(t => { 41 | FormEngine.setSelectOptionFromExternalSource(l, t.value, t.textContent, t.getAttribute("title"), e, t); 42 | }); 43 | } 44 | } 45 | }); 46 | new SelectBoxFilter(this.availableOptionsElement); 47 | } 48 | } -------------------------------------------------------------------------------- /Documentation/Developer/EventDispatcher/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | =========================== 5 | EventDispatcher (PSR-14 Events) 6 | =========================== 7 | 8 | 9 | Register ClassifyContent Event Listener 10 | ------------------------------------------ 11 | 12 | 1. Open your Services.yaml or Services.php file from your Extension. 13 | 14 | 2. Add the following code snippet to register the `ClassifyContent` event listener: 15 | 16 | .. code-block:: php 17 | 18 | YourVendor\YourSitepackage\EventListner\ClassifyContent: 19 | tags: 20 | - name: event.listener 21 | 22 | 23 | Handling the 'ClassifyContentEvent' 24 | ------------------------------ 25 | 26 | The `ClassifyContent` event listener handles the `ClassifyContentEvent` and performs custom logic. 27 | 28 | 1. Create a new PHP class in your TYPO3 extension, e.g., `EXT:your_sitepackage/Classes/EventListner/ClassifyContent.php`. 29 | 30 | 3. Implement the `__invoke` method in the class, which will handle the event. The method should accept a `ClassifyContentEvent` object as a parameter. 31 | 32 | .. code-block:: php 33 | 34 | namespace YourVendor\YourSitepackage\EventListner; 35 | 36 | use CodingFreaks\CfCookiemanager\Event\ClassifyContentEvent; 37 | use TYPO3\CMS\Extbase\Utility\DebuggerUtility; 38 | 39 | class ClassifyContent 40 | { 41 | /** 42 | * Handle the ClassifyContentEvent, handle the provider URL and set the service identifier. 43 | * 44 | * @param ClassifyContentEvent $event The ClassifyContentEvent object 45 | */ 46 | public function __invoke(ClassifyContentEvent $event): void 47 | { 48 | // Custom logic goes here 49 | 50 | // Example: Dump a debug message 51 | // DebuggerUtility::var_dump("SitePackage invoke"); 52 | 53 | // Example: Access the provider URL 54 | // DebuggerUtility::var_dump($event->getProviderURL()); 55 | 56 | // Example: Set the service identifier 57 | // $event->setServiceIdentifier("TESTServiceIdentifier"); 58 | } 59 | } 60 | 61 | .. Tip:: 62 | Please note that you need to replace: YourVendor\YourSitepackage\ with the correct namespaces for your extension. -------------------------------------------------------------------------------- /Tests/Acceptance/Backend/Frontend/CookieFrontendCest.php: -------------------------------------------------------------------------------- 1 | amOnUrl('http://web/typo3temp/var/tests/acceptance'); 36 | $I->see('Consent Required'); 37 | } 38 | 39 | /** 40 | * 41 | * This test checks if the iframemanager blocks the embeded YouTube iframe 42 | * @test 43 | */ 44 | public function isIframeManagerOverridingSeeLoadNotice(BackendTester $I): void 45 | { 46 | $I->see('Load YouTube videos','.c-l-b'); 47 | } 48 | 49 | /** 50 | * 51 | * This test checks if the module is visible in the backend, and the warning is shown if no data is in the database if a root page is selected 52 | * @test 53 | */ 54 | public function isConsentModuleLaunching(BackendTester $I): void 55 | { 56 | $I->see('Consent Required'); //See Consent Required 57 | $I->click("#c-p-bn"); //Click Accept all / Consent primary Btn 58 | $I->wait(4); 59 | $I->switchToIFrame('[src="https://www.youtube-nocookie.com/embed/RCJdPiogUIk"]'); //Switch to YT Video 60 | $I->see("Don't make random HTTP requests"); //Check if YT Video is loaded 61 | $I->switchToMainFrame(); 62 | $I->click('[data-cc="c-settings"]'); //Click on Settings 63 | $I->see("Cookie Categories"); //Check if Cookie Settings Modal is visible 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /Tests/Unit/Domain/Model/ExternalScriptsTest.php: -------------------------------------------------------------------------------- 1 | subject = new \CodingFreaks\CfCookiemanager\Domain\Model\ExternalScripts(); 28 | } 29 | 30 | protected function tearDown(): void 31 | { 32 | parent::tearDown(); 33 | } 34 | 35 | #[Test] 36 | public function getNameReturnsInitialValueForString(): void 37 | { 38 | self::assertSame( 39 | '', 40 | $this->subject->getName() 41 | ); 42 | } 43 | 44 | #[Test] 45 | public function setNameForStringSetsName(): void 46 | { 47 | $this->subject->setName('Conceived at T3CON10'); 48 | 49 | self::assertEquals('Conceived at T3CON10', $this->subject->getName()); 50 | } 51 | 52 | #[Test] 53 | public function getLinkReturnsInitialValueForString(): void 54 | { 55 | self::assertSame( 56 | '', 57 | $this->subject->getLink() 58 | ); 59 | } 60 | 61 | #[Test] 62 | public function setLinkForStringSetsLink(): void 63 | { 64 | $this->subject->setLink('Conceived at T3CON10'); 65 | 66 | self::assertEquals('Conceived at T3CON10', $this->subject->getLink()); 67 | } 68 | 69 | #[Test] 70 | public function getAsyncReturnsInitialValueForBool(): void 71 | { 72 | self::assertFalse($this->subject->getAsync()); 73 | } 74 | 75 | #[Test] 76 | public function setAsyncForBoolSetsAsync(): void 77 | { 78 | $this->subject->setAsync(true); 79 | 80 | self::assertEquals(true, $this->subject->getAsync()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Classes/Domain/Model/Variables.php: -------------------------------------------------------------------------------- 1 | name; 52 | } 53 | 54 | /** 55 | * Sets the name 56 | * 57 | * @param string $name 58 | * @return void 59 | */ 60 | public function setName(string $name) 61 | { 62 | $this->name = $name; 63 | } 64 | 65 | /** 66 | * Returns the identifier 67 | * 68 | * @return string 69 | */ 70 | public function getIdentifier() 71 | { 72 | return $this->identifier; 73 | } 74 | 75 | /** 76 | * Sets the identifier 77 | * 78 | * @param string $identifier 79 | * @return void 80 | */ 81 | public function setIdentifier(string $identifier) 82 | { 83 | $this->identifier = $identifier; 84 | } 85 | 86 | /** 87 | * Returns the value 88 | * 89 | * @return string 90 | */ 91 | public function getValue() 92 | { 93 | return $this->value; 94 | } 95 | 96 | /** 97 | * Sets the value 98 | * 99 | * @param string $value 100 | * @return void 101 | */ 102 | public function setValue(string $value) 103 | { 104 | $this->value = $value; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Build/phpunit/FunctionalTests.xml: -------------------------------------------------------------------------------- 1 | 10 | 30 | 31 | 32 | 36 | ../../Tests/Functional/ 37 | 38 | 39 | 40 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Resources/Public/JavaScript/TutorialTours/TourFunctions.js: -------------------------------------------------------------------------------- 1 | // Instance the tour 2 | // console.log(TF.selectFormEngineInput("identifier","")); 3 | // console.log(TF.selectFormEngineInput("cookie_services")); 4 | // console.log(TF.selectFormEngineInput("cookie_services",".t3js-formengine-field-group .form-multigroup-item:nth-child(2) .form-wizards-element")); 5 | 6 | 7 | function selectFormEngineInput(name, selector = "", elementOnly = false) { 8 | // Select all elements with attribute containing 'data[*]' 9 | var elements = document.querySelectorAll('input[data-formengine-input-name*="data"],textarea[name*="data"],select[name*="data"],input.inlineRecord'); 10 | // Loop through the elements and find the one with the unknown identifier 11 | var targetElement; 12 | for (var i = 0; i < elements.length; i++) { 13 | var element = elements[i]; 14 | var attributeName = element.getAttribute('data-formengine-input-name'); 15 | 16 | if (typeof attributeName === "object") { 17 | attributeName = element.getAttribute('name'); 18 | } 19 | // Check if the identifier is unknown (denoted by *) 20 | if (attributeName.includes('[' + name + ']')) { 21 | targetElement = element; 22 | break; 23 | } 24 | } 25 | 26 | if(targetElement === undefined) { 27 | try { 28 | //Try to find a CKEditor5 element 29 | targetElement = document.querySelector(`typo3-rte-ckeditor-ckeditor5[id*='${name}']`); 30 | if(targetElement === null) { 31 | console.log("No element found with the id containing: " + name); 32 | } 33 | } catch (error) { 34 | console.error("Error while trying to find element with id containing: " + name, error); 35 | } 36 | } 37 | 38 | // Perform operations on the targetElement 39 | if (targetElement) { 40 | if (selector !== "") { 41 | if (elementOnly === true) { 42 | return targetElement.closest(selector); 43 | } 44 | return targetElement.closest(selector); 45 | } 46 | if (elementOnly === true) { 47 | return targetElement; 48 | } 49 | return targetElement.closest(selector); 50 | } 51 | } 52 | 53 | 54 | 55 | 56 | export {selectFormEngineInput}; -------------------------------------------------------------------------------- /Tests/Unit/Domain/Model/VariablesTest.php: -------------------------------------------------------------------------------- 1 | subject = new \CodingFreaks\CfCookiemanager\Domain\Model\Variables(); 29 | } 30 | 31 | protected function tearDown(): void 32 | { 33 | parent::tearDown(); 34 | } 35 | 36 | #[Test] 37 | public function getNameReturnsInitialValueForString(): void 38 | { 39 | self::assertSame( 40 | '', 41 | $this->subject->getName() 42 | ); 43 | } 44 | 45 | #[Test] 46 | public function setNameForStringSetsName(): void 47 | { 48 | $this->subject->setName('Conceived at T3CON10'); 49 | 50 | self::assertEquals('Conceived at T3CON10', $this->subject->getName()); 51 | } 52 | 53 | #[Test] 54 | public function getIdentifierReturnsInitialValueForString(): void 55 | { 56 | self::assertSame( 57 | '', 58 | $this->subject->getIdentifier() 59 | ); 60 | } 61 | 62 | #[Test] 63 | public function setIdentifierForStringSetsIdentifier(): void 64 | { 65 | $this->subject->setIdentifier('Conceived at T3CON10'); 66 | 67 | self::assertEquals('Conceived at T3CON10', $this->subject->getIdentifier()); 68 | } 69 | 70 | #[Test] 71 | public function getValueReturnsInitialValueForString(): void 72 | { 73 | self::assertSame( 74 | '', 75 | $this->subject->getValue() 76 | ); 77 | } 78 | 79 | #[Test] 80 | public function setValueForStringSetsValue(): void 81 | { 82 | $this->subject->setValue('Conceived at T3CON10'); 83 | 84 | self::assertEquals('Conceived at T3CON10', $this->subject->getValue()); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Classes/Widgets/Provider/ConsentTrackingDonutAcceptTypes.php: -------------------------------------------------------------------------------- 1 | getNumberOfRecords("necessary"); 32 | $custom = $this->getNumberOfRecords("custom"); 33 | $all = $this->getNumberOfRecords("all"); 34 | 35 | return [ 36 | 'labels' => [ 37 | "Strictly Necessary", 38 | "Custom selection", 39 | "All", 40 | ], 41 | 'datasets' => [ 42 | [ 43 | 'backgroundColor' => [ 44 | '#263238', 45 | '#546e7a', 46 | '#78909c', 47 | ], 48 | 'data' => [$necessary, $custom,$all], 49 | ], 50 | ], 51 | ]; 52 | } 53 | 54 | protected function getNumberOfRecords(string $type): int 55 | { 56 | $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_cfcookiemanager_domain_model_tracking'); 57 | return (int)$queryBuilder 58 | ->count('uid') 59 | ->from('tx_cfcookiemanager_domain_model_tracking') 60 | ->where( 61 | $queryBuilder->expr()->eq( 62 | 'consent_type', 63 | $queryBuilder->createNamedParameter($type, Connection::PARAM_STR) 64 | ) 65 | ) 66 | ->executeQuery() 67 | ->fetchOne(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Classes/Domain/Model/ExternalScripts.php: -------------------------------------------------------------------------------- 1 | name; 52 | } 53 | 54 | /** 55 | * Sets the name 56 | * 57 | * @param string $name 58 | * @return void 59 | */ 60 | public function setName(string $name) 61 | { 62 | $this->name = $name; 63 | } 64 | 65 | /** 66 | * Returns the link 67 | * 68 | * @return string 69 | */ 70 | public function getLink() 71 | { 72 | return $this->link; 73 | } 74 | 75 | /** 76 | * Sets the link 77 | * 78 | * @param string $link 79 | * @return void 80 | */ 81 | public function setLink(string $link) 82 | { 83 | $this->link = $link; 84 | } 85 | 86 | /** 87 | * Returns the async 88 | * 89 | * @return bool 90 | */ 91 | public function getAsync() 92 | { 93 | return $this->async; 94 | } 95 | 96 | /** 97 | * Sets the async 98 | * 99 | * @param bool $async 100 | * @return void 101 | */ 102 | public function setAsync(bool $async) 103 | { 104 | $this->async = $async; 105 | } 106 | 107 | /** 108 | * Returns the boolean state of async 109 | * 110 | * @return bool 111 | */ 112 | public function isAsync() 113 | { 114 | return $this->async; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Classes/Middleware/ModifyHtmlContent.php: -------------------------------------------------------------------------------- 1 | getAttribute('frontend.typoscript')->getFlatSettings(); 31 | $constantConfig = [ 32 | "disable_plugin" => intval($fullTypoScript["plugin.tx_cfcookiemanager_cookiefrontend.frontend.disable_plugin"]) ?? 0, 33 | "script_blocking" => intval($fullTypoScript["plugin.tx_cfcookiemanager_cookiefrontend.frontend.script_blocking"]) ?? 0, 34 | ]; 35 | 36 | // let it generate a response 37 | $response = $handler->handle($request); 38 | if ($response instanceof NullResponse) { 39 | return $response; 40 | } 41 | 42 | // extract the content 43 | $body = $response->getBody(); 44 | $body->rewind(); 45 | $content = $response->getBody()->getContents(); 46 | $rootLine = $request->getAttribute('frontend.page.information')->getRootline()[0]; 47 | 48 | // if Plugin is Enabled, hook the Content for GDPR Compliance 49 | if((int)$constantConfig["disable_plugin"] !== 1){ 50 | $cfRenderUtility = GeneralUtility::makeInstance(\CodingFreaks\CfCookiemanager\Utility\RenderUtility::class); 51 | $content = $cfRenderUtility->cfHook($content, $constantConfig,$rootLine); 52 | } 53 | 54 | // push new content back into the response 55 | $body = new Stream('php://temp', 'rw'); 56 | $body->write($content); 57 | return $response->withBody($body); 58 | } 59 | } -------------------------------------------------------------------------------- /Resources/Public/Backend/Css/bootstrap-tour.css: -------------------------------------------------------------------------------- 1 | .tour-backdrop { 2 | position: absolute; 3 | z-index: 1100; 4 | background-color: #000; 5 | opacity: 0.8; 6 | filter: alpha(opacity=80); 7 | } 8 | .popover[class*="tour-"] { 9 | z-index: 1102; 10 | max-width: 100%; 11 | font-size: 14px; 12 | } 13 | .popover[class*="tour-"] .popover-navigation { 14 | padding: 9px 14px; 15 | overflow: hidden; 16 | } 17 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] { 18 | float: right; 19 | } 20 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"], 21 | .popover[class*="tour-"] .popover-navigation *[data-role="next"], 22 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] { 23 | cursor: pointer; 24 | } 25 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled, 26 | .popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled, 27 | .popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled { 28 | cursor: default; 29 | } 30 | .popover[class*="tour-"].orphan { 31 | position: fixed; 32 | margin-top: 0; 33 | } 34 | .popover[class*="tour-"].orphan .arrow { 35 | display: none; 36 | } 37 | 38 | .tour-step-element-reflex{ 39 | position: relative; 40 | animation: pulse-red 2s infinite !important; 41 | background: #e9cd2a !important; 42 | button{ 43 | background: #e9cd2a !important; 44 | } 45 | [data-color-scheme="dark"] & { 46 | background: #846f00 !important; 47 | button{ 48 | background: #846f00 !important; 49 | } 50 | } 51 | 52 | } 53 | 54 | .tour-step-element-reflex a{ 55 | background: #e9cd2a !important; 56 | [data-color-scheme="dark"] & { 57 | background: #846f00 !important; 58 | } 59 | } 60 | 61 | .data-role-end,.data-role-prev { 62 | display: none; 63 | } 64 | 65 | .tour-tour .btn-secondary{ 66 | background: rgb(115, 115, 115); 67 | color: white; 68 | } 69 | 70 | @keyframes pulse-red { 71 | 0% { 72 | transform: scale(0.95); 73 | box-shadow: 0 0 0 0 red; 74 | } 75 | 76 | 70% { 77 | transform: scale(1); 78 | box-shadow: 0 0 0 0 red; 79 | } 80 | 81 | 100% { 82 | transform: scale(0.95); 83 | box-shadow: 0 0 0 0 red; 84 | } 85 | } 86 | .force-end-tour p{ 87 | margin: 0; 88 | } 89 | .force-end-tour{ 90 | cursor: pointer; 91 | position: absolute; 92 | bottom: 0; 93 | right: 0; 94 | color: black; 95 | padding: 20px; 96 | background: orange; 97 | font-weight: bold; 98 | } 99 | 100 | .tour-no-scroll{ 101 | overflow: hidden; 102 | } -------------------------------------------------------------------------------- /Configuration/Icons.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 6 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/Extension.svg' 7 | ], 8 | 9 | 'cf_cookiemanager-position-bottom-right' => [ 10 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 11 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/bottom-right.svg' 12 | ], 13 | 'cf_cookiemanager-position-bottom-left' => [ 14 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 15 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/bottom-left.svg' 16 | ], 17 | 'cf_cookiemanager-position-bottom-center' => [ 18 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 19 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/bottom-center.svg' 20 | ], 21 | 22 | 'cf_cookiemanager-position-top-center' => [ 23 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 24 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/top-center.svg' 25 | ], 26 | 'cf_cookiemanager-position-top-right' => [ 27 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 28 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/top-right.svg' 29 | ], 30 | 'cf_cookiemanager-position-top-left' => [ 31 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 32 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/top-left.svg' 33 | ], 34 | 35 | 'cf_cookiemanager-position-center-center' => [ 36 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 37 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/center-center.svg' 38 | ], 39 | 'cf_cookiemanager-position-center-right' => [ 40 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 41 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/center-right.svg' 42 | ], 43 | 'cf_cookiemanager-position-center-left' => [ 44 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 45 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/backend/position/center-left.svg' 46 | ], 47 | 'cfcookiemanager-cookie-list' => [ 48 | 'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, 49 | 'source' => 'EXT:cf_cookiemanager/Resources/Public/Icons/cookie-list.svg', 50 | ], 51 | ]; 52 | -------------------------------------------------------------------------------- /Resources/Public/JavaScript/TutorialTours/CategoryTour.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | 3 | import { selectFormEngineInput } from '@codingfreaks/cf-cookiemanager/TutorialTours/TourFunctions.js'; 4 | // Instance the tour 5 | const tour = { 6 | onStart: function() { 7 | sessionStorage.setItem("currentTour", "CategoryTour"); 8 | return true; 9 | }, 10 | onEnd: function() { 11 | sessionStorage.setItem("currentTour", ""); 12 | return true; 13 | }, 14 | debug: true, 15 | backdrop: true, 16 | storage: window.sessionStorage, 17 | steps: [ 18 | { 19 | //path: "/", 20 | element: "#start-categories-tour", 21 | title: "Cookie Categories Tour", 22 | placement: "bottom", 23 | content: "Categories containing all third-party Providers, such as Youtube, Vimeo, Google Maps, etc.." 24 | }, 25 | { 26 | element: "#externalmedia", 27 | orphan: true, 28 | title: "Configure 'External Media'.", 29 | content: "In this Example we configure the Youtube Provider,
which is part of the Category External Media." 30 | }, 31 | { 32 | path: $("#externalmedia").find(".settings-item-head-right a").attr("href"), 33 | // element: TF.selectFormEngineInput("cookie_services",".t3js-formengine-field-group .form-multigroup-item:nth-child(2) .form-wizards-element"), 34 | element: selectFormEngineInput("cookie_services",".form-group",false), 35 | placement: "top", 36 | orphan: true, 37 | title: "Add Cookie Services", 38 | content: "Search for the Youtube provider and add it to the list of Cookie Services" 39 | }, 40 | { 41 | // element: TF.selectFormEngineInput("cookie_services",".t3js-formengine-field-group .form-multigroup-item:nth-child(1) .form-wizards-element"), 42 | element: selectFormEngineInput("cookie_services",".form-group",false), 43 | orphan: true, 44 | placement: "top", 45 | title: "Youtube Provider added", 46 | content: "Done, the Youtube Provider is now part of the Category 'External Media'." 47 | }, 48 | { 49 | element: "body > div.module > div.module-docheader.t3js-module-docheader > div.module-docheader-bar.module-docheader-bar-buttons.t3js-module-docheader-bar.t3js-module-docheader-bar-buttons > div.module-docheader-bar-column-left > div > button", 50 | orphan: true, 51 | reflex: true, 52 | title: "Save and close", 53 | content: "Done, save and close the configuration." 54 | }, 55 | ] 56 | }; 57 | 58 | export default tour; 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Resources/Public/JavaScript/FormEngine/Element/Extra/SelectBoxFilter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the TYPO3 CMS project. 3 | * 4 | * It is free software; you can redistribute it and/or modify it under 5 | * the terms of the GNU General Public License, either version 2 6 | * of the License, or any later version. 7 | * 8 | * For the full copyright and license information, please read the 9 | * LICENSE.txt file that was distributed with this source code. 10 | * 11 | * The TYPO3 project - inspiring people to share! 12 | */ 13 | import RegularEvent from "@typo3/core/event/regular-event.js"; 14 | 15 | var Selectors; 16 | !function (e) { 17 | e.fieldContainerSelector = ".t3js-formengine-field-group", e.filterTextFieldSelector = ".t3js-formengine-multiselect-filter-textfield", e.filterSelectFieldSelector = ".t3js-formengine-multiselect-filter-dropdown" 18 | }(Selectors || (Selectors = {})); 19 | 20 | class SelectBoxFilter { 21 | constructor(e) { 22 | this.selectElement = null, this.filterText = "", this.availableOptions = null, this.selectElement = e, this.initializeEvents() 23 | } 24 | 25 | static toggleOptGroup(e) { 26 | const t = e.parentElement; 27 | t instanceof HTMLOptGroupElement && (0 === t.querySelectorAll("option:not([hidden]):not([disabled]):not(.hidden)").length ? t.hidden = !0 : (t.hidden = !1, t.disabled = !1, t.classList.remove("hidden"))) 28 | } 29 | 30 | initializeEvents() { 31 | const e = this.selectElement.closest(".form-wizards-element"); 32 | null !== e && (new RegularEvent("input", (e => { 33 | this.filter(e.target.value,true) 34 | })).delegateTo(e, Selectors.filterTextFieldSelector), new RegularEvent("change", (e => { 35 | this.filter(e.target.value,false) 36 | })).delegateTo(e, Selectors.filterSelectFieldSelector)) 37 | } 38 | 39 | filter(e,freetext) { 40 | this.filterText = e; 41 | null === this.availableOptions && (this.availableOptions = this.selectElement.querySelectorAll("option")); 42 | const t = new RegExp(e, "i"); 43 | if(freetext === true){ 44 | this.availableOptions.forEach(l => { 45 | l.hidden = e.length > 0 && null === l.getAttribute("title").match(t), SelectBoxFilter.toggleOptGroup(l) 46 | }) 47 | }else{ 48 | this.availableOptions.forEach(l => { 49 | if(l.getAttribute("data-category") !== undefined && l.getAttribute("data-category") !== null && l.getAttribute("data-category") !== "" && l.getAttribute("data-category") !== " ") { 50 | l.hidden = e.length > 0 && null === l.getAttribute("data-category").match(t); SelectBoxFilter.toggleOptGroup(l) 51 | } 52 | }) 53 | } 54 | } 55 | } 56 | 57 | export default SelectBoxFilter; -------------------------------------------------------------------------------- /ext_localconf.php: -------------------------------------------------------------------------------- 1 | 'list,track' 15 | ], 16 | // non-cacheable actions 17 | [ 18 | \CodingFreaks\CfCookiemanager\Controller\CookieFrontendController::class => 'track' 19 | ], 20 | \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT 21 | ); 22 | 23 | \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( 24 | 'CfCookiemanager', 25 | 'CookieList', 26 | [ 27 | \CodingFreaks\CfCookiemanager\Controller\CookieFrontendController::class => 'cookieList' 28 | ], 29 | // non-cacheable actions 30 | [ 31 | \CodingFreaks\CfCookiemanager\Controller\CookieFrontendController::class => '' 32 | ], 33 | \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT 34 | ); 35 | 36 | \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( 37 | 'CfCookiemanager', 38 | 'IframeManagerThumbnail', 39 | [ 40 | \CodingFreaks\CfCookiemanager\Controller\CookieFrontendController::class => 'thumbnail' 41 | ], 42 | // non-cacheable actions 43 | [ 44 | \CodingFreaks\CfCookiemanager\Controller\CookieFrontendController::class => '' 45 | ], 46 | \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT 47 | ); 48 | 49 | })(); 50 | 51 | /* Refactored MultipleSideBySide Element for Typo3 13 Style Standards */ 52 | $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1287112284] = [ 53 | 'nodeName' => 'CfSelectMultipleSideBySide', 54 | 'priority' => '70', 55 | 'class' => \CodingFreaks\CfCookiemanager\Form\Element\CfSelectMultipleSideBySideElement13::class, 56 | ]; 57 | 58 | $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = "cf_thumbnail"; 59 | 60 | // Register css for backend Modal of API-changes and API-Updates 61 | $GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']['cf_cookiemanager'] = 'EXT:cf_cookiemanager/Resources/Public/Backend/Css/BackendModal.css'; 62 | 63 | //Hook for the DataHandler - Submit Shared Cconfig 64 | $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['cf_cookiemanager'] = \CodingFreaks\CfCookiemanager\Hooks\DataHandlerHook::class; -------------------------------------------------------------------------------- /Documentation/Installation/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | .. _installation: 4 | 5 | ============ 6 | Installation 7 | ============ 8 | 9 | To use the CodingFreaks cookie plugin in Typo3, you must first install it in your Typo3 system. 10 | This can be done by using Composer. 11 | 12 | 13 | .. code-block:: bash 14 | 15 | composer require codingfreaks/cf-cookiemanager 16 | 17 | 18 | Include TypoScript template (Deprecated since v12) 19 | ________________________ 20 | 21 | To properly use the plugin, it is necessary to include the basic TypoScript provided by the extension. 22 | To do this, go to the :guilabel:`Web > Template` module in the Typo3 backend, select the root page, and switch to the 23 | :guilabel:`Info/Modify` view. 24 | 25 | From there, click on :guilabel:`Edit the whole template record` and switch to the Includes tab. 26 | Next, add the :guilabel:`CodingFreaks Cookie Manager (cf_cookiemanager)` template from the list on the right. 27 | 28 | 29 | Use Site sets (for Typo3 v13+) 30 | ________________________ 31 | 32 | 1. **Add the Site Set in the Backend**: 33 | 34 | - Go to the Typo3 backend. 35 | - Navigate to **Sites**. 36 | - Open your site configuration. 37 | - Add the `CodingFreaks/cf-cookiemanager` Site Set as a dependency. 38 | 39 | 2. **Alternatively, Use YAML Configuration**: 40 | 41 | You can also add the Site Set directly in your site's `config.yaml` file: 42 | 43 | .. code-block:: yaml 44 | :caption: typo3installPath/config/sites/your_site/config.yaml 45 | 46 | base: 'https://example.com/' 47 | rootPageId: 1 48 | dependencies: 49 | - CodingFreaks/cf-cookiemanager 50 | 51 | 52 | Backend Installation / Dataset Import 53 | ________________________ 54 | 55 | This extension provides an external API to automatically create cookie assignments to individual services in various languages. 56 | 57 | To install the preconfigured data sets, go to the Typo3 backend and select the :guilabel:`Cookie Settings` module in the Web tab. 58 | Click on Start Configuration and follow the instructions. 59 | 60 | .. figure:: ../Images/Installation/installation_screen.png 61 | :class: with-shadow 62 | :alt: Introduction Package 63 | :width: 100% 64 | 65 | Installation Screen 66 | 67 | .. Tip:: 68 | 69 | The extension automatically configures itself and creates the corresponding data set and Language overlays from site config.yaml. 70 | The Locals in the site config.yaml are used for the right language. 71 | 72 | 73 | You can now Configure the Extension in the :guilabel:`Cookie Settings` module. 74 | 75 | 76 | .. Tip:: 77 | If the import is unsuccessful: 78 | 79 | Disable the extension via Composer :guilabel:`composer rem codingfreaks/cf-cookiemanager`. 80 | 81 | Remove Mysql-Table fia Typo3 :guilabel:`Database Analyzer`. 82 | 83 | Install Extension again with :guilabel:`composer require codingfreaks/cf-cookiemanager`. 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Documentation/Developer/CustomServices/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | =========================== 5 | Custom Service Configuration 6 | =========================== 7 | 8 | 9 | 10 | Leaflet & Openstreetmap 11 | ====================== 12 | 13 | 14 | First of all Include leaflet and Openstreetmap like you wish in Typo3. 15 | 16 | Add the attribute :guilabel:`data-service="leaflet"` to the script. 17 | Add the attribute :guilabel:`type="text/plain` to the script. 18 | Ensure that the service with the identifier :guilabel:`leaflet` exists and is enabled. 19 | 20 | You can now Include the Script in any Place of your HTML Dom. 21 | The Cookie Manager hooks it on Consent accept. 22 | :guilabel:`` 23 | 24 | For an quick an dirty way to test use this code. 25 | 26 | .. code-block:: html 27 | 28 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 79 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codingfreaks/cf-cookiemanager", 3 | "type": "typo3-cms-extension", 4 | "description": "Manage cookies, scripts, and GDPR compliance on your Typo3 website with CodingFreaks Typo3 Cookie Manager. Customize cookie banners, streamline workflow, and enhance user experience. Ensure GDPR compliance and take control of cookie management with our Typo3 cookie management extension. Visit the official Typo3 Documentation page to learn more.", 5 | "authors": [ 6 | { 7 | "name": "Florian Eibisberger", 8 | "role": "Developer", 9 | "email": "cookiemanager@coding-freaks.com", 10 | "homepage": "https://coding-freaks.com" 11 | } 12 | ], 13 | "keywords": [ 14 | "typo3", 15 | "cookie", 16 | "plugin", 17 | "manager", 18 | "cms", 19 | "consent", 20 | "GDPR", 21 | "scanner", 22 | "DSGVO" 23 | ], 24 | "license": "GPL-2.0-or-later", 25 | "require": { 26 | "php": "^8.1 || ^8.2 || ^8.3 || ^8.4", 27 | "typo3/cms-core": "^13.4.15 || ^14.0", 28 | "typo3/cms-dashboard": "^13.4 || ^14.0", 29 | "typo3/cms-install": "^13.4 || ^14.0", 30 | "ext-xml": "*", 31 | "ext-libxml": "*", 32 | "ext-curl": "*" 33 | }, 34 | 35 | "require-dev": { 36 | "phpunit/phpunit": "^12", 37 | "typo3/cms-dashboard": "^13.4 || ^14.0", 38 | "typo3/cms-tstemplate": "^13.4 || ^14.0", 39 | "typo3/cms-frontend": "^13.4 || ^14.0", 40 | "typo3/cms-seo": "^13.4 || ^14.0", 41 | "typo3/testing-framework": "^9.0", 42 | "typo3/cms-install": "^13.4 || ^14.0", 43 | "typo3/cms-fluid-styled-content": "^13.4 || ^14.0", 44 | "codeception/codeception": "^5.0.10", 45 | "codeception/lib-asserts": "^2.1.0", 46 | "codeception/module-asserts": "^3.0.0", 47 | "codeception/module-cli": "^2.0.1", 48 | "codeception/module-filesystem": "^3.0.0", 49 | "codeception/module-webdriver": "^4.0.0" 50 | }, 51 | "autoload": { 52 | "psr-4": { 53 | "CodingFreaks\\CfCookiemanager\\": "Classes" 54 | } 55 | }, 56 | "autoload-dev": { 57 | "psr-4": { 58 | "CodingFreaks\\CfCookiemanager\\Tests\\": "Tests" 59 | } 60 | }, 61 | "replace": { 62 | "typo3-ter/cf-cookiemanager": "self.version" 63 | }, 64 | "config": { 65 | "vendor-dir": ".Build/vendor", 66 | "bin-dir": ".Build/bin", 67 | "allow-plugins": { 68 | "typo3/class-alias-loader": true, 69 | "typo3/cms-composer-installers": true 70 | } 71 | }, 72 | "scripts": { 73 | "post-autoload-dump": [ 74 | "TYPO3\\TestingFramework\\Composer\\ExtensionTestEnvironment::prepare" 75 | ] 76 | }, 77 | "extra": { 78 | "typo3/cms": { 79 | "web-dir": ".Build/public", 80 | "extension-key": "cf_cookiemanager" 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Documentation/Configuration/ExtensionSettings/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | ============= 5 | Extension Settings 6 | ============= 7 | 8 | 9 | Available Settings 10 | ------------------ 11 | 12 | The following settings can be configured in the admin backend module "settings", Extension Configuration. 13 | 14 | 15 | Available Constants 16 | ------------------ 17 | 18 | - disable_plugin (boolean): Disables the plugin in the frontend and middleware if set to 1. 19 | - script_blocking (boolean): Blocks third-party scripts and iframes. Only unregistered scripts/iframes are not loaded if the user has not given consent. 20 | (Feature): The loading of content such as iframes and scripts from third-party sources, can be Disabled by adding a Data Atribute to the Script or Iframe (data-script-blocking-disabled="true") 21 | 22 | - scan_api_key (string): Used for authorization/scan API (optional). Authorization on the API side is required to upgrade scan limits and using the Thumbnail API. 23 | - scan_api_secret (string): Used for authorization/scan API (optional). Authorization on the API side is required to upgrade scan limits and using the Thumbnail API. 24 | - end_point (string): Specifies the endpoint for the scan API (optional). The default value is https://coding-freaks.com/api. 25 | - thumbnail_api_enabled (boolean): Enables the thumbnail API. If active, the API is used to generate thumbnails for the iframe preview if content is blocked. (Uses external endpoint), the files are stored in /typo3temp/cfthumbnails/* 26 | 27 | - tracking_enabled (boolean): Enables cookie consent tracking. If active, the first action of the visitor in the consent modal is tracked before any external JavaScript is loaded. 28 | - tracking_obfuscate (boolean): Obfuscates the tracking data. If set to 1, the tracking js is obfuscated before it is sent to the browser. (uses javascript eval function) 29 | - autorun_consent (integer): Run Consent Modal on Page Load 30 | - force_consent (integer): Enable if you want to block page navigation until user consent action 31 | - revision_version (integer): Used for consent revision. If changed, all users will need to opt-in again. 32 | - cookie_expiration (integer): Specifies the number of days before the cookie expires. The default value is 365 days (one year). 33 | - cookie_path (string): Specifies the path where the cookie will be set. The default value is /. 34 | - cookie_domain (string): Domain where the cookie will be set. The default value is window.location.hostname. 35 | - hide_from_bots (boolean): If set to 1, the cookie plugin will not run when a bot/crawler/webdriver is detected. 36 | 37 | - cf_consentmodal_template (string): Specifies the path to the consent modal template in the extension. 38 | - cf_settingsmodal_template (string): Specifies the path to the settings modal template in the extension. 39 | - cf_settingsmodal_category_template (string): Specifies the path to the settings modal category item template in the extension. 40 | 41 | 42 | Note that these settings are provided as an example and may vary depending on the version of the extension you are using. -------------------------------------------------------------------------------- /Classes/Widgets/Provider/ConsentTrackingDataProvider.php: -------------------------------------------------------------------------------- 1 | days = $days; 40 | } 41 | 42 | public function getChartData(): array 43 | { 44 | $this->calculateDataForLastDays(); 45 | 46 | return [ 47 | 'labels' => $this->labels, 48 | 'datasets' => [ 49 | [ 50 | 'label' => "Consent-Modal activities", 51 | 'backgroundColor' => WidgetApi::getDefaultChartColors()[4], 52 | 'border' => 0, 53 | 'data' => $this->data, 54 | ], 55 | ], 56 | ]; 57 | } 58 | 59 | protected function getNumberOfErrorsInPeriod(int $start, int $end): int 60 | { 61 | $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_cfcookiemanager_domain_model_tracking'); 62 | return (int)$queryBuilder 63 | ->count('*') 64 | ->from('tx_cfcookiemanager_domain_model_tracking') 65 | ->where( 66 | $queryBuilder->expr()->gte( 67 | 'consent_date', 68 | $queryBuilder->createNamedParameter($start, Connection::PARAM_INT) 69 | ), 70 | $queryBuilder->expr()->lte( 71 | 'consent_date', 72 | $queryBuilder->createNamedParameter($end, Connection::PARAM_INT) 73 | ) 74 | ) 75 | ->executeQuery() 76 | ->fetchOne(); 77 | } 78 | 79 | protected function calculateDataForLastDays(): void 80 | { 81 | $format = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] ?: 'Y-m-d'; 82 | 83 | for ($daysBefore = $this->days; $daysBefore >= 0; $daysBefore--) { 84 | $this->labels[] = date($format, (int)strtotime('-' . $daysBefore . ' day')); 85 | $startPeriod = (int)strtotime('-' . $daysBefore . ' day 0:00:00'); 86 | $endPeriod = (int)strtotime('-' . $daysBefore . ' day 23:59:59'); 87 | 88 | $this->data[] = $this->getNumberOfErrorsInPeriod($startPeriod, $endPeriod); 89 | } 90 | } 91 | 92 | protected function getLanguageService(): LanguageService 93 | { 94 | return $GLOBALS['LANG']; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/settings/settings_links.svg: -------------------------------------------------------------------------------- 1 | Reject allAccept allSaveCookie SettingsSelect the categories of cookies you want to acceptRequired CookiesRequired Cookies -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/settings/settings_rechts.svg: -------------------------------------------------------------------------------- 1 | Reject allAccept allSaveCookie SettingsSelect the categories of cookies you want to acceptRequired CookiesRequired Cookies -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/settings/settings_mitte.svg: -------------------------------------------------------------------------------- 1 | Reject allAccept allSaveCookie SettingsSelect the categories of cookies you want to acceptRequired CookiesRequired Cookies -------------------------------------------------------------------------------- /Classes/Domain/Repository/CookieRepository.php: -------------------------------------------------------------------------------- 1 | apiRepository = $apiRepository; 49 | } 50 | 51 | /** 52 | * @param \CodingFreaks\CfCookiemanager\Domain\Repository\CookieServiceRepository $cookieServiceRepository 53 | */ 54 | public function injectCookieServiceRepository(\CodingFreaks\CfCookiemanager\Domain\Repository\CookieServiceRepository $cookieServiceRepository) 55 | { 56 | $this->cookieServiceRepository = $cookieServiceRepository; 57 | } 58 | 59 | public function getCookieBySysLanguage($storage, $langUid = 0) 60 | { 61 | $query = $this->createQuery(); 62 | 63 | if ($langUid !== false) { 64 | $languageAspect = new LanguageAspect((int)$langUid, (int)$langUid, LanguageAspect::OVERLAYS_ON); //$languageAspect->getOverlayType()); 65 | $query->getQuerySettings()->setLanguageAspect($languageAspect); 66 | $query->getQuerySettings()->setStoragePageIds($storage); 67 | } 68 | 69 | $query->getQuerySettings()->setIgnoreEnableFields(false)->setStoragePageIds($storage); 70 | $cookies = $query->execute(); 71 | $allCookies = []; 72 | foreach ($cookies as $category) { 73 | $allCookies[] = $category; 74 | } 75 | return $allCookies; 76 | } 77 | 78 | /** 79 | * @param $identifier 80 | */ 81 | public function getCookieByName($identifier, $langUid = 0, $storage = [1]) 82 | { 83 | $query = $this->createQuery(); 84 | $languageAspect = new LanguageAspect($langUid, $langUid, LanguageAspect::OVERLAYS_ON); //$languageAspect->getOverlayType()); 85 | $query->getQuerySettings()->setLanguageAspect($languageAspect); 86 | $query->getQuerySettings()->setStoragePageIds($storage); 87 | $query->matching($query->logicalAnd($query->equals('name', $identifier))); 88 | $query->setOrderings(array("crdate" => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING))->setLimit(1); 89 | return $query->execute(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_links_oben.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_links_unten.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_mitte_oben.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_rechts_oben.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_unten_mitte.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_links_mitte.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_mitte_mitte.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_rechts_mitte.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Resources/Public/Icons/backend/position/consent/modal_rechts_unten.svg: -------------------------------------------------------------------------------- 1 | Consent RequiredTo optimize and continuously improve our website for you, we use cookies. You can accept all cookies or choose only specific ones. You can change these settings at any time.SettingsRejectAccept -------------------------------------------------------------------------------- /Documentation/Configuration/AutoConfiguration/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Includes.txt 2 | 3 | 4 | =========================== 5 | Auto Configuration (Beta) 6 | =========================== 7 | This extension is able to automatically configure the cookie categories and services for you. 8 | 9 | Please note that the output of this tool may not be completely accurate. 10 | 11 | It is intended to assist with analyzing a website's cookie behavior and should not be relied on as the sole source of information. 12 | 13 | Use it as a starting point for your analysis. 14 | 15 | How to use: 16 | This is done by using the :ref:`CF-Cookie-API ` service. You can find the configuration in the :guilabel:`Cookie Settings` module in the backend. 17 | 18 | 19 | Start Scan 20 | ______________________________ 21 | 22 | By clicking on the Scan button, an external web scanner will scan 10 pages of your website and detect any embedded scripts, iframes, and cookies. 23 | 24 | These can be imported using the Import button after a successful scan. 25 | 26 | Existing services will be ignored and only new services will be added if they are detected. 27 | 28 | You can use a custom sitemap.xml to target the 10 Pages. (ex. https://cookiedemo.coding-freaks.com/mysitemap.xml) 29 | 30 | 31 | Scan Reports from your Website 32 | ______________________________ 33 | 34 | Easily and efficiently manage your services with Autoconfiguration. 35 | 36 | Here, you can easily import any discovered services on your website. 37 | 38 | If you want to learn more about your scans, simply click on the "Open Report" button. This link will take you to our detailed report website, where you will receive a complete overview of all your imported services, iFrames, and scripts. 39 | 40 | Ensure your services are always up-to-date and up-to-standards by easily and quickly scanning your website. 41 | 42 | Scanning & importing 43 | ______________________________ 44 | 45 | By clicking on the Scan button, an external web scanner is called up, which analyzes the website and outputs the Scan Report table. 46 | 47 | The Cookie consent ins accepted by default to find all cookies. 48 | 49 | If you want to scan the website without accepting the cookie consent, or use custom settings to assist you by finding Services, you can use the public scanner on https://coding-freaks.com/cookie-scanner or the API (https://coding-freaks.com/cookie-database). 50 | 51 | These can be imported using the Import button after a successful scan and then edited as required. 52 | 53 | Existing services will be ignored and only new services will be added if they are detected. 54 | 55 | :guilabel:`Important`: Unknown Services are ignored, and needed to be added manually. 56 | 57 | This can be found on the Report page, by clicking on the :guilabel:`Open Report` button. 58 | 59 | Unknown Services have no Identifier and you need to set the Provider in the Cookie Service manually. 60 | 61 | As example the Scanner or your found an Service like: 62 | 63 | - Provider: grimming.panomax.com/. 64 | - Cookie: _gat_panomax 65 | 66 | The service is unknown, add it now by adding a new Cookie Service in the backend. 67 | 68 | The Provider field is used to compare the original URL with the URL from the embedded iframe or script. 69 | 70 | You can separate different providers by using a comma. :guilabel:`grimming.panomax.com/,roma.panomax.com` or simply use the domain name :guilabel:`.panomax.com` to match all subdomains. 71 | 72 | .. figure:: ../../Images/Ui/backend_cookie_service_provider.png 73 | :class: with-shadow 74 | :alt: Scan 75 | :width: 100% -------------------------------------------------------------------------------- /Classes/Service/SiteService.php: -------------------------------------------------------------------------------- 1 | siteFinder->getSiteByPageId($pageId); 44 | $siteLanguages = $site->getAvailableLanguages($backendUser, false, $pageId); 45 | 46 | foreach ($siteLanguages as $siteLanguage) { 47 | $languageAspectToTest = LanguageAspectFactory::createFromSiteLanguage($siteLanguage); 48 | // @extensionScannerIgnoreLine 49 | $siteLangUID = $siteLanguage->getLanguageId(); // Ignore Line of false positive 50 | $page = $this->pageRepository->getPageOverlay($this->pageRepository->getPage($pageId), $siteLangUID); 51 | if ($this->pageRepository->isPageSuitableForLanguage($page, $languageAspectToTest)) { 52 | $languages[$siteLangUID] = [ 53 | 'title' => $siteLanguage->getTitle(), 54 | 'locale-short' => $this->fallbackToLocales($siteLanguage->getLocale()->getName()) 55 | ]; 56 | } 57 | } 58 | } catch (SiteNotFoundException $e) { 59 | // do nothing 60 | } 61 | return $languages; 62 | } 63 | 64 | /** 65 | * Determines the locale based on the provided locale string. 66 | * 67 | * This method checks if the provided locale string contains any of the allowed unknown locales. 68 | * If a match is found, it returns the first matching locale. If no match is found, it defaults to "en". 69 | * 70 | * @param string $locale The locale string to check. 71 | * @return string The matched locale or "en" if no match is found. 72 | */ 73 | public function fallbackToLocales($locale): string 74 | { 75 | //fallback to english, if no API KEY is used on a later state. 76 | $allowedUnknownLocales = [ 77 | "de", 78 | "en", 79 | "es", 80 | "it", 81 | "fr", 82 | "nl", 83 | "pl", 84 | "pt", 85 | "da", 86 | ]; 87 | foreach ($allowedUnknownLocales as $allowedUnknownLocale) { 88 | if (strpos(strtolower($locale), $allowedUnknownLocale) !== false) { 89 | //return the first match 90 | return $allowedUnknownLocale; 91 | } 92 | } 93 | return "en"; //fallback to english 94 | } 95 | 96 | 97 | 98 | } -------------------------------------------------------------------------------- /Tests/Unit/Utility/ContentScriptBlockerTest.php: -------------------------------------------------------------------------------- 1 | renderUtility = $this->mockRenderUtilityWithClassifyContentMock(); 20 | } 21 | 22 | #[Test] 23 | private function mockRenderUtilityWithClassifyContentMock(): RenderUtility 24 | { 25 | // Mock EventDispatcherInterface 26 | $eventDispatcher = $this->createMock(EventDispatcherInterface::class); 27 | 28 | // Create RenderUtility instance (partial mock) 29 | $renderUtility = $this->getMockBuilder(RenderUtility::class) 30 | ->setConstructorArgs([$eventDispatcher]) 31 | ->onlyMethods(['classifyContent']) // Specify the method to mock 32 | ->getMock(); 33 | 34 | // Set up the mock behavior for classifyContent method 35 | $renderUtility 36 | ->method('classifyContent') 37 | ->willReturn(''); // Return empty string to simulate no service 38 | 39 | return $renderUtility; 40 | } 41 | 42 | #[Test] 43 | public function testOverrideScriptWithValidHtmlWithScriptBlocking() 44 | { 45 | // Arrange 46 | $html = ' \'*üöam '; 47 | $html_default = ' \'*üöam '; 48 | 49 | // Act 50 | $result = $this->renderUtility->replaceScript($html, ["script_blocking" => 1],["uid" =>1]); //Simulate script blocking, with script blocking disabled by data tag, should return the same html 51 | $result_default = $this->renderUtility->replaceScript($html_default, ["script_blocking" => 1],["uid" =>1]); //Simulate script blocking, with a default script tag, should get blocked 52 | $result_default_off = $this->renderUtility->replaceScript($html_default, ["script_blocking" => 0],["uid" =>1]); //Simulate a default installation with script blocking disabled, should return the same html 53 | 54 | // Assert 55 | $this->assertStringContainsString('type="text/javascript"', $result_default_off); 56 | $this->assertStringContainsString('type="text/plain"', $result_default); 57 | $this->assertStringContainsString('type="text/javascript"', $result); 58 | $this->assertStringContainsString('\'*üöam', $result); 59 | } 60 | 61 | 62 | #[Test] 63 | public function testOverrideIframesWithValidHtmlScriptBlocking() 64 | { 65 | // Arrange 66 | $html = '

\'*üöam

'; 67 | 68 | // Act 69 | $result = $this->renderUtility->replaceIframes($html, ["script_blocking" => 1],["uid" => 1]); 70 | 71 | // Assert 72 | $this->assertStringContainsString('d', $result); 73 | $this->assertStringContainsString('src="https://www.youtube.com/embed/AuBXeF5acqE"', $result); 74 | 75 | } 76 | 77 | 78 | 79 | } 80 | --------------------------------------------------------------------------------