├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── composer.json └── src ├── CookieMonster.php ├── assets └── CookieMonsterAsset.php ├── js ├── CookieMonster.js └── CookieMonster.min.js └── views └── box.php /.gitattributes: -------------------------------------------------------------------------------- 1 | /.github export-ignore 2 | /tests export-ignore 3 | /phpunit.xml.dist export-ignore 4 | /infection.json.dist export-ignore 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | composer.lock 4 | .phpunit.result.cache 5 | infection.log 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Bizley 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of yii2-cookiemonster nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yii2-cookiemonster 2 | Yii 2 extension to manage cookie warning 3 | 4 | ![Latest Stable Version](https://img.shields.io/packagist/v/bizley/cookiemonster.svg) 5 | ![Total Downloads](https://img.shields.io/packagist/dt/bizley/cookiemonster.svg) 6 | ![License](https://img.shields.io/packagist/l/bizley/cookiemonster.svg) 7 | [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fbizley%2Fyii2-cookiemonster%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/bizley/yii2-cookiemonster/master) 8 | 9 | ## What is it for? 10 | In 2009, the European Union sought new regulations as part of an "e-privacy" directive, seeing cookies as a potential 11 | threat to privacy, because users often don't know they are being tracked. 12 | This extension adds the information about cookies for the Yii website. 13 | 14 | ## Requirements 15 | Yii 2 16 | 17 | ## Installation 18 | Get it through composer by adding the package to your composer.json: 19 | 20 | ```php 21 | { 22 | "require": { 23 | "bizley/cookiemonster": "*" 24 | } 25 | } 26 | ``` 27 | 28 | Or run `composer require bizley/cookiemonster`. 29 | 30 | 31 | ## Usage 32 | Add this code in your main template file just before `endBody() ?>` 33 | 34 | 35 | 36 | This will render widget with all default options (and 'top' layout). 37 | If you want to configure it add options array. 38 | 39 | 40 | 41 | All options (and options' options) are described below. 42 | For example if you want to use custom message on the button and use 'bottom' layout set: 43 | 44 | [ 46 | 'buttonMessage' => 'OK', // instead of default 'I understand' 47 | ], 48 | 'mode' => 'bottom' 49 | ]); ?> 50 | 51 | ## Configuration 52 | You can set widget options by passing array to the widget() method with the following keys: 53 | 54 | * `box` - __array__ CSS class and styles and HTML options for div 55 | * `content` - __array__ warning and button message 56 | * `cookie` - __array__ cookie options 57 | * `mode` - __string__ widget layout selection 58 | * `params` - __mixed__ user's parameters to pass to the custom widget layout 59 | 60 | ## `box` options 61 | * `addButtonStyle` - __array__ list of button CSS style options to be added or replaced with new values 62 | i.e. 'padding-right' => '20px', 'font-weight' => 'bold' 63 | * `addInnerStyle` - __array__ list of inner div CSS style options to be added or replaced with new values 64 | * `addOuterStyle` - __array__ list of outer div CSS style options to be added or replaced with new values 65 | * `buttonHtmlOptions` - __array__ list of button HTML options to be added (except style and class) 66 | * `classButton` - __string__ button class or classes (separated by spaces), default 'CookieMonsterOk' 67 | * `classInner` - __string__ inner div class or classes (separated by spaces) 68 | * `classOuter` - __string__ outer div class or classes (separated by spaces), default 'CookieMonsterBox' 69 | * `innerHtmlOptions` - __array__ list of inner div HTML options to be added (except style and class) 70 | * `outerHtmlOptions` - __array__ list of outer div HTML options to be added (except style and class) 71 | * `replaceButtonStyle` - __array__ list of button CSS style options to be replaced with new values or removed 72 | i.e. 'margin-left' => '10px', 'font-size' => false 73 | * `replaceInnerStyle` - __array__ list of inner div CSS style options to be replaced with new values or removed 74 | * `replaceOuterStyle` - __array__ list of outer div CSS style options to be replaced with new values or removed 75 | * `setButtonStyle` - __array__ list of button CSS style options to be set replacing the default ones 76 | * `setInnerStyle` - __array__ list of inner div CSS style options to be set replacing the default ones 77 | * `setOuterStyle` - __array__ list of outer div CSS style options to be set replacing the default ones 78 | * `view` - __string__ path to the custom view (required if $mode is set to 'custom'), for views outside the widget 79 | folder use alias path i.e. '@app/views/cookie' 80 | 81 | ## `content` options 82 | * `buttonMessage` - __string__ button original message as in Yii::t() $message, default 'I understand' 83 | * `buttonParams` - __array__ parameters to be applied to the buttonMessage as in Yii::t() $params, default array() 84 | * `category` - __string__ message category as in Yii::t() $category, default 'app' 85 | * `language` - __string__ target language as in Yii::t() $language, default null 86 | * `mainMessage` - __string__ main original message as in Yii::t() $message, default 'We use cookies on our websites to 87 | help us offer you the best online experience. By continuing to use our website, you are agreeing to our use of 88 | cookies. Alternatively, you can manage them in your browser settings.' 89 | * `mainParams` - __array__ parameters to be applied to the mainMessage as in Yii::t() $params, default array() 90 | 91 | ## `cookie` options 92 | * `domain` - __string__ domain name for the cookie, default host portion of the current document location 93 | * `expires` - __integer__ number of days this cookie will be valid for, default 30 94 | * `max-age` - __integer__ max cookie age in seconds 95 | * `path` - __string__ path for the cookie, default '/' 96 | * `secure` - __boolean__ whether cookie should be transmitted over secure protocol as https, default false 97 | * `sameSite` - __string__ 'lax' (default), 'strict', or 'none' 98 | 99 | ## `mode` possible values 100 | * `bottom` - bottom strip 101 | * `box` - bottom right box 102 | * `custom` - custom mode defined by user (requires `box[view]` to be set) 103 | * `top` - top strip, default 104 | 105 | ## Default layouts 106 | 107 | ### bottom 108 | 109 | ```html 110 | 115 | ``` 116 | 117 | ### box 118 | 119 | ```html 120 | 125 | ``` 126 | 127 | ### top 128 | 129 | ```html 130 | 135 | ``` 136 | 137 | ## Yii 1.1 version 138 | You can find Yii 1.1 version at https://github.com/bizley/Yii-CookieMonster 139 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bizley/cookiemonster", 3 | "type": "yii2-extension", 4 | "description": "Yii extension to manage cookie warning.", 5 | "keywords": ["yii2", "widget", "cookiemonster", "cookie", "warning", "privacy"], 6 | "license": "BSD-3-Clause", 7 | "support": { 8 | "source": "https://github.com/bizley/yii2-cookiemonster", 9 | "issues": "https://github.com/bizley/yii2-cookiemonster/issues" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Paweł Bizley Brzozowski", 14 | "email": "pawel@positive.codes" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=5.4", 19 | "yiisoft/yii2": "*" 20 | }, 21 | "require-dev": { 22 | "infection/infection": "*", 23 | "php": ">=7.4", 24 | "phpunit/phpunit": "^9.5", 25 | "roave/security-advisories": "dev-latest" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "bizley\\cookiemonster\\": "src/" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "bizley\\tests\\": "tests/" 35 | } 36 | }, 37 | "repositories": [ 38 | { 39 | "type": "composer", 40 | "url": "https://asset-packagist.org" 41 | } 42 | ], 43 | "config": { 44 | "allow-plugins": { 45 | "infection/extension-installer": true, 46 | "yiisoft/yii2-composer": true 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/CookieMonster.php: -------------------------------------------------------------------------------- 1 | '20px', 'font-weight' => 'bold' 34 | * - addInnerStyle: array 35 | * list of inner div CSS style options to be added or replaced with new values 36 | * - addOuterStyle: array 37 | * list of outer div CSS style options to be added or replaced with new values 38 | * - buttonHtmlOptions: array 39 | * list of button HTML options to be added (except style and class) 40 | * - classButton: string 41 | * button class or classes (separated by spaces), default 'CookieMonsterOk' 42 | * - classInner: string 43 | * inner div class or classes (separated by spaces) 44 | * - classOuter: string 45 | * outer div class or classes (separated by spaces), default 'CookieMonsterBox' 46 | * - innerHtmlOptions: array 47 | * list of inner div HTML options to be added (except style and class) 48 | * - outerHtmlOptions: array 49 | * list of outer div HTML options to be added (except style and class) 50 | * - replaceButtonStyle: array 51 | * list of button CSS style options to be replaced with new values or removed 52 | * i.e. 'margin-left' => '10px', 'font-size' => false 53 | * - replaceInnerStyle: array 54 | * list of inner div CSS style options to be replaced with new values or removed 55 | * - replaceOuterStyle: array 56 | * list of outer div CSS style options to be replaced with new values or removed 57 | * - setButtonStyle: array 58 | * list of button CSS style options to be set replacing the default ones 59 | * - setInnerStyle: array 60 | * list of inner div CSS style options to be set replacing the default ones 61 | * - setOuterStyle: array 62 | * list of outer div CSS style options to be set replacing the default ones 63 | * - view: string 64 | * path to the custom view (required if $mode is set to 'custom'), for views outside the widget folder 65 | * use alias path, i.e. '@app/views/cookie' 66 | */ 67 | public $box = []; 68 | 69 | /** 70 | * @var array parameters for the texts. 71 | * Available options: 72 | * - buttonMessage: string 73 | * button original message as in Yii::t() $message, default 'I understand' 74 | * - buttonParams: array 75 | * parameters to be applied to the buttonMessage as in Yii::t() $params, default [] 76 | * - category: string 77 | * message category as in Yii::t() $category, default 'app' 78 | * - language: string 79 | * target language as in Yii::t() $language, default null 80 | * - mainMessage: string 81 | * main original message as in Yii::t() $message, default 'We use cookies on our websites to help us offer you 82 | * the best online experience. By continuing to use our website, you are agreeing to our use of cookies. 83 | * Alternatively, you can manage them in your browser settings.' 84 | * - mainParams: array 85 | * parameters to be applied to the mainMessage as in Yii::t() $params, default [] 86 | */ 87 | public $content = []; 88 | 89 | /** 90 | * @var array parameters for the cookie 91 | * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie 92 | * Available options: 93 | * - domain: string 94 | * domain name for the cookie, default host portion of the current document location 95 | * - expires: integer 96 | * number of days this cookie will be valid for, default 30 97 | * - max-age: integer 98 | * max cookie age in seconds 99 | * - path: string 100 | * path for the cookie, default '/' 101 | * - secure: boolean 102 | * whether cookie should be transmitted over secure protocol as https, default false 103 | * - sameSite: string 104 | * either 'strict', 'lax' (default), or 'none' 105 | */ 106 | public $cookie = []; 107 | 108 | /** 109 | * @var string name of the mode to be used 110 | * Available options: 111 | * - bottom: bottom strip 112 | * - box: bottom right box 113 | * - custom: custom mode defined by user (requires $box[view] to be set) 114 | * - top: top strip, default 115 | */ 116 | public $mode = 'top'; 117 | 118 | /** 119 | * @var mixed parameter or parameters passed to the custom user's view in case this is needed 120 | */ 121 | public $params; 122 | 123 | /** 124 | * @var array list of button's HTML options 125 | */ 126 | protected $buttonHtml = []; 127 | 128 | /** 129 | * @var array list of button's CSS styles 130 | */ 131 | protected $buttonStyle = []; 132 | 133 | /** 134 | * @var array list of CSS class options 135 | */ 136 | protected $classOptions = []; 137 | 138 | /** 139 | * @var array list of content options 140 | */ 141 | protected $contentOptions = []; 142 | 143 | /** 144 | * @var array list of cookie options 145 | */ 146 | protected $cookieOptions = []; 147 | 148 | /** 149 | * @var string custom view path 150 | */ 151 | protected $cookieView = ''; 152 | 153 | /** 154 | * @var array list of inner div HTML options 155 | */ 156 | protected $innerHtml = []; 157 | 158 | /** 159 | * @var array list of inner div CSS styles 160 | */ 161 | protected $innerStyle = []; 162 | 163 | /** 164 | * @var array list of outer div HTML options 165 | */ 166 | protected $outerHtml = []; 167 | 168 | /** 169 | * @var array list of outer div CSS styles 170 | */ 171 | protected $outerStyle = []; 172 | 173 | /** 174 | * Adds class option, removes dot and hash. 175 | * @param mixed $name option name 176 | * @param mixed $value option value 177 | * Since 1.1 this method is public. 178 | */ 179 | public function addClassOption($name, $value) 180 | { 181 | if (!empty($value)) { 182 | $value = trim($value); 183 | if (strpos($value, '.') === 0 || strpos($value, '#') === 0) { 184 | $value = substr($value, 1); 185 | } 186 | if ($value !== '') { 187 | $this->addOption('class', $name, $value); 188 | } 189 | } 190 | } 191 | 192 | /** 193 | * Adds content option. 194 | * @param mixed $name option name 195 | * @param mixed $value option value 196 | * Since 1.1 this method is public. 197 | */ 198 | public function addContentOption($name, $value) 199 | { 200 | if (!empty($value)) { 201 | $this->addOption('content', $name, trim($value)); 202 | } 203 | } 204 | 205 | /** 206 | * Adds boolean cookie option. 207 | * @param mixed $name option name 208 | * @param bool|mixed $value option value 209 | * Since 1.1 this method is public. 210 | */ 211 | public function addCookieBoolOption($name, $value) 212 | { 213 | if ($value !== null) { 214 | $this->addOption('cookie', $name, (bool)$value); 215 | } 216 | } 217 | 218 | /** 219 | * Adds integer cookie option. 220 | * @param mixed $name option name 221 | * @param mixed $value option value 222 | * Since 1.1 this method is public. 223 | */ 224 | public function addCookieIntOption($name, $value) 225 | { 226 | if ($value !== null) { 227 | $this->addOption('cookie', $name, (int)$value); 228 | } 229 | } 230 | 231 | /** 232 | * Adds cookie option, removes '; name=' part. 233 | * @param mixed $name option name 234 | * @param mixed $value option value 235 | * Since 1.1 this method is public. 236 | */ 237 | public function addCookieOption($name, $value) 238 | { 239 | $value = preg_replace("~^;? ?$name=~", '', trim($value)); 240 | if ($value !== '') { 241 | if ($name === 'sameSite' && !in_array($value, ['strict', 'lax', 'none'])) { 242 | return; 243 | } 244 | $this->addOption('cookie', $name, $value); 245 | } 246 | } 247 | 248 | /** 249 | * Adds option of certain type. 250 | * @param mixed $type type name 251 | * @param mixed $name option name 252 | * @param mixed $value option value 253 | * Since 1.1 this method is public. 254 | */ 255 | public function addOption($type, $name, $value) 256 | { 257 | $this->{$type . 'Options'}[$name] = $value; 258 | } 259 | 260 | /** 261 | * Adds content parameters option. 262 | * @param mixed $name option name 263 | * @param array $value list of parameters 264 | * Since 1.1 this method is public. 265 | */ 266 | public function addParamsOption($name, $value) 267 | { 268 | if ($value && is_array($value)) { 269 | $this->addOption('content', $name, $value); 270 | } 271 | } 272 | 273 | /** 274 | * Adds the CSS styles for selected part. 275 | * @param int $what number of part 276 | * @param array $value list of styles 277 | */ 278 | protected function addStyle($what, $value) 279 | { 280 | if (is_array($value)) { 281 | $type = 'inner'; 282 | switch ($what) { 283 | case 0: 284 | $type = 'outer'; 285 | break; 286 | case 2: 287 | $type = 'button'; 288 | break; 289 | } 290 | foreach ($value as $name => $set) { 291 | if (!empty($set) && is_string($set)) { 292 | $this->{$type . 'Style'}[$name] = str_replace(';', '', trim($set)); 293 | } 294 | } 295 | } 296 | } 297 | 298 | /** 299 | * Adds the CSS styles for inner part. 300 | * @param array $value list of styles 301 | * @since 1.1 302 | */ 303 | public function addInnerStyle($value) 304 | { 305 | $this->addStyle(1, $value); 306 | } 307 | 308 | /** 309 | * Adds the CSS styles for outer part. 310 | * @param array $value list of styles 311 | * @since 1.1 312 | */ 313 | public function addOuterStyle($value) 314 | { 315 | $this->addStyle(0, $value); 316 | } 317 | 318 | /** 319 | * Adds the CSS styles for button part. 320 | * @param array $value list of styles 321 | * @since 1.1 322 | */ 323 | public function addButtonStyle($value) 324 | { 325 | $this->addStyle(2, $value); 326 | } 327 | 328 | /** 329 | * Validates box parameters. 330 | */ 331 | protected function checkBox() 332 | { 333 | if (is_array($this->box)) { 334 | foreach ($this->box as $name => $value) { 335 | switch ($name) { 336 | case 'classOuter': 337 | $this->addClassOption('classOuter', $value); 338 | break; 339 | case 'classButton': 340 | $this->addClassOption('classButton', $value); 341 | break; 342 | case 'classInner': 343 | $this->addClassOption('classInner', $value); 344 | break; 345 | case 'replaceOuterStyle': 346 | $this->replaceOuterStyle($value); 347 | break; 348 | case 'replaceInnerStyle': 349 | $this->replaceInnerStyle($value); 350 | break; 351 | case 'replaceButtonStyle': 352 | $this->replaceButtonStyle($value); 353 | break; 354 | case 'addOuterStyle': 355 | $this->addOuterStyle($value); 356 | break; 357 | case 'addInnerStyle': 358 | $this->addInnerStyle($value); 359 | break; 360 | case 'addButtonStyle': 361 | $this->addButtonStyle($value); 362 | break; 363 | case 'setOuterStyle': 364 | $this->setOuterStyle($value); 365 | break; 366 | case 'setInnerStyle': 367 | $this->setInnerStyle($value); 368 | break; 369 | case 'setButtonStyle': 370 | $this->setButtonStyle($value); 371 | break; 372 | case 'view': 373 | $this->setCookieView($value); 374 | break; 375 | case 'outerHtmlOptions': 376 | $this->setOuterHtmlOptions($value); 377 | break; 378 | case 'innerHtmlOptions': 379 | $this->setInnerHtmlOptions($value); 380 | break; 381 | case 'buttonHtmlOptions': 382 | $this->setButtonHtmlOptions($value); 383 | break; 384 | } 385 | } 386 | } 387 | } 388 | 389 | /** 390 | * Validates content parameters. 391 | */ 392 | protected function checkContent() 393 | { 394 | if (is_array($this->content)) { 395 | foreach ($this->content as $name => $value) { 396 | switch ($name) { 397 | case 'category': 398 | case 'mainMessage': 399 | case 'buttonMessage': 400 | case 'language': 401 | $this->addContentOption($name, $value); 402 | break; 403 | case 'mainParams': 404 | case 'buttonParams': 405 | $this->addParamsOption($name, $value); 406 | break; 407 | } 408 | } 409 | } 410 | } 411 | 412 | /** 413 | * Validates cookie parameters. 414 | */ 415 | protected function checkCookie() 416 | { 417 | if (is_array($this->cookie)) { 418 | foreach ($this->cookie as $name => $value) { 419 | switch ($name) { 420 | case 'domain': 421 | case 'path': 422 | case 'sameSite': 423 | $this->addCookieOption($name, $value); 424 | break; 425 | case 'max-age': 426 | case 'expires': 427 | $this->addCookieIntOption($name, $value); 428 | break; 429 | case 'secure': 430 | $this->addCookieBoolOption($name, $value); 431 | break; 432 | } 433 | } 434 | } 435 | } 436 | 437 | /** 438 | * Initialises the JS file, prepares the JSON js options. 439 | */ 440 | protected function initCookie() 441 | { 442 | $cookieOptions = Json::encode( 443 | array_merge( 444 | $this->cookieOptions, 445 | [ 446 | 'classOuter' => str_replace(' ', '.', $this->classOptions['classOuter']), 447 | 'classInner' => str_replace(' ', '.', $this->classOptions['classInner']), 448 | 'classButton' => str_replace(' ', '.', $this->classOptions['classButton']), 449 | ] 450 | ) 451 | ); 452 | $view = $this->getView(); 453 | assets\CookieMonsterAsset::register($view); 454 | $view->registerJs("CookieMonster.init($cookieOptions);"); 455 | } 456 | 457 | /** 458 | * Prepares the list of parameters to send to the view. 459 | * @return array 460 | */ 461 | protected function prepareViewParams() 462 | { 463 | $outerStyle = []; 464 | $innerStyle = []; 465 | $buttonStyle = []; 466 | 467 | foreach ($this->outerStyle as $name => $value) { 468 | $outerStyle[] = $name . ':' . $value; 469 | } 470 | foreach ($this->innerStyle as $name => $value) { 471 | $innerStyle[] = $name . ':' . $value; 472 | } 473 | foreach ($this->buttonStyle as $name => $value) { 474 | $buttonStyle[] = $name . ':' . $value; 475 | } 476 | 477 | return [ 478 | 'content' => $this->contentOptions, 479 | 'outerHtmlOptions' => array_merge( 480 | $this->outerHtml, 481 | [ 482 | 'style' => implode(';', $outerStyle), 483 | 'class' => $this->classOptions['classOuter'], 484 | ] 485 | ), 486 | 'innerHtmlOptions' => array_merge( 487 | $this->innerHtml, 488 | [ 489 | 'style' => implode(';', $innerStyle), 490 | 'class' => $this->classOptions['classInner'], 491 | ] 492 | ), 493 | 'buttonHtmlOptions' => array_merge( 494 | $this->buttonHtml, 495 | [ 496 | 'style' => implode(';', $buttonStyle), 497 | 'class' => $this->classOptions['classButton'], 498 | ] 499 | ), 500 | 'params' => $this->params, 501 | ]; 502 | } 503 | 504 | /** 505 | * Replaces the CSS styles for selected part. 506 | * @param int $what number of part 507 | * @param array $value list of styles 508 | */ 509 | protected function replaceStyle($what, $value) 510 | { 511 | if (is_array($value)) { 512 | $type = 'inner'; 513 | switch ($what) { 514 | case 0: 515 | $type = 'outer'; 516 | break; 517 | case 2: 518 | $type = 'button'; 519 | break; 520 | } 521 | foreach ($value as $name => $set) { 522 | if (isset($this->{$type . 'Style'}[$name])) { 523 | if ($set === false || $set === null) { 524 | unset($this->{$type . 'Style'}[$name]); 525 | } elseif (is_string($set)) { 526 | $this->{$type . 'Style'}[$name] = str_replace(';', '', trim($set)); 527 | } 528 | } 529 | } 530 | } 531 | } 532 | 533 | /** 534 | * Replaces the CSS styles for inner part. 535 | * @param array $value list of styles 536 | * @since 1.1 537 | */ 538 | public function replaceInnerStyle($value) 539 | { 540 | $this->replaceStyle(1, $value); 541 | } 542 | 543 | /** 544 | * Replaces the CSS styles for outer part. 545 | * @param array $value list of styles 546 | * @since 1.1 547 | */ 548 | public function replaceOuterStyle($value) 549 | { 550 | $this->replaceStyle(0, $value); 551 | } 552 | 553 | /** 554 | * Replaces the CSS styles for button part. 555 | * @param array $value list of styles 556 | * @since 1.1 557 | */ 558 | public function replaceButtonStyle($value) 559 | { 560 | $this->replaceStyle(2, $value); 561 | } 562 | 563 | /** 564 | * Runs the widget. 565 | * @return string 566 | */ 567 | public function run() 568 | { 569 | $this->setMode(); 570 | $this->checkBox(); 571 | $this->checkCookie(); 572 | $this->checkContent(); 573 | $this->setDefaults(); 574 | $this->initCookie(); 575 | 576 | return $this->render( 577 | $this->mode === 'custom' ? $this->cookieView : 'box', 578 | $this->prepareViewParams() 579 | ); 580 | } 581 | 582 | /** 583 | * Sets default values. 584 | */ 585 | protected function setDefaults() 586 | { 587 | if (empty($this->contentOptions['category'])) { 588 | $this->contentOptions['category'] = 'app'; 589 | } 590 | if (!array_key_exists('mainParams', $this->contentOptions)) { 591 | $this->contentOptions['mainParams'] = []; 592 | } 593 | if (!array_key_exists('buttonParams', $this->contentOptions)) { 594 | $this->contentOptions['buttonParams'] = []; 595 | } 596 | if (!array_key_exists('language', $this->contentOptions)) { 597 | $this->contentOptions['language'] = null; 598 | } 599 | if (!array_key_exists('mainMessage', $this->contentOptions)) { 600 | $this->contentOptions['mainMessage'] = 'We use cookies on our websites to help us offer you the best online experience. By continuing to use our website, you are agreeing to our use of cookies. Alternatively, you can manage them in your browser settings.'; 601 | } 602 | if (!array_key_exists('buttonMessage', $this->contentOptions)) { 603 | $this->contentOptions['buttonMessage'] = 'I understand'; 604 | } 605 | if (!array_key_exists('path', $this->cookieOptions)) { 606 | $this->cookieOptions['path'] = '/'; 607 | } 608 | if (!array_key_exists('expires', $this->cookieOptions)) { 609 | $this->cookieOptions['expires'] = 30; 610 | } 611 | if (!array_key_exists('secure', $this->cookieOptions)) { 612 | $this->cookieOptions['secure'] = false; 613 | } 614 | if (!array_key_exists('classOuter', $this->classOptions)) { 615 | $this->classOptions['classOuter'] = 'CookieMonsterBox'; 616 | } 617 | if (!array_key_exists('classInner', $this->classOptions)) { 618 | $this->classOptions['classInner'] = ''; 619 | } 620 | if (!array_key_exists('classButton', $this->classOptions)) { 621 | $this->classOptions['classButton'] = 'CookieMonsterOk'; 622 | } 623 | } 624 | 625 | /** 626 | * Sets HTML options for selected part. 627 | * @param int $what number of part 628 | * @param array $value list of options 629 | */ 630 | protected function setHtmlOptions($what, $value) 631 | { 632 | if (is_array($value)) { 633 | $type = 'inner'; 634 | switch ($what) { 635 | case 0: 636 | $type = 'outer'; 637 | break; 638 | case 2: 639 | $type = 'button'; 640 | break; 641 | } 642 | foreach ($value as $name => $set) { 643 | if (is_string($set) && $name !== 'class' && $name !== 'style') { 644 | $this->{$type . 'Html'}[$name] = trim($set); 645 | } 646 | } 647 | } 648 | } 649 | 650 | /** 651 | * Sets HTML options for inner part. 652 | * @param array $value list of options 653 | * @since 1.1 654 | */ 655 | public function setInnerHtmlOptions($value) 656 | { 657 | $this->setHtmlOptions(1, $value); 658 | } 659 | 660 | /** 661 | * Sets HTML options for outer part. 662 | * @param array $value list of options 663 | * @since 1.1 664 | */ 665 | public function setOuterHtmlOptions($value) 666 | { 667 | $this->setHtmlOptions(0, $value); 668 | } 669 | 670 | /** 671 | * Sets HTML options for button part. 672 | * @param array $value list of options 673 | * @since 1.1 674 | */ 675 | public function setButtonHtmlOptions($value) 676 | { 677 | $this->setHtmlOptions(2, $value); 678 | } 679 | 680 | /** 681 | * Sets the mode with default CSS styles. 682 | */ 683 | protected function setMode() 684 | { 685 | $this->outerStyle = [ 686 | 'display' => 'none', 687 | 'z-index' => 10000, 688 | 'position' => 'fixed', 689 | 'background-color' => '#fff', 690 | 'font-size' => '12px', 691 | 'color' => '#000', 692 | ]; 693 | $this->innerStyle = ['margin' => '10px']; 694 | $this->buttonStyle = ['margin-left' => '10px']; 695 | 696 | switch ($this->mode) { 697 | case 'bottom': 698 | $this->outerStyle = array_merge( 699 | $this->outerStyle, 700 | [ 701 | 'bottom' => 0, 702 | 'left' => 0, 703 | 'width' => '100%', 704 | 'box-shadow' => '0 -2px 2px #000', 705 | ] 706 | ); 707 | break; 708 | case 'box': 709 | $this->outerStyle = array_merge( 710 | $this->outerStyle, 711 | [ 712 | 'bottom' => '20px', 713 | 'right' => '20px', 714 | 'width' => '300px', 715 | 'box-shadow' => '-2px 2px 2px #000', 716 | 'border-radius' => '10px', 717 | ] 718 | ); 719 | break; 720 | case 'custom': 721 | $this->outerStyle = []; 722 | $this->innerStyle = []; 723 | $this->buttonStyle = []; 724 | break; 725 | default: 726 | $this->outerStyle = array_merge( 727 | $this->outerStyle, 728 | [ 729 | 'top' => 0, 730 | 'left' => 0, 731 | 'width' => '100%', 732 | 'box-shadow' => '0 2px 2px #000', 733 | ] 734 | ); 735 | } 736 | } 737 | 738 | /** 739 | * Sets the CSS styles for selected part. 740 | * @param int $what number of part 741 | * @param array $value list of styles 742 | */ 743 | protected function setStyle($what, $value) 744 | { 745 | if (is_array($value)) { 746 | $type = 'inner'; 747 | switch ($what) { 748 | case 0: 749 | $type = 'outer'; 750 | break; 751 | case 2: 752 | $type = 'button'; 753 | break; 754 | } 755 | $tmp = []; 756 | foreach ($value as $name => $set) { 757 | if (!empty($set) && is_string($set)) { 758 | $tmp[$name] = str_replace(';', '', trim($set)); 759 | } 760 | } 761 | $this->{$type . 'Style'} = $tmp; 762 | } 763 | } 764 | 765 | /** 766 | * Sets the CSS styles for inner part. 767 | * @param array $value list of styles 768 | * @since 1.1 769 | */ 770 | public function setInnerStyle($value) 771 | { 772 | $this->setStyle(1, $value); 773 | } 774 | 775 | /** 776 | * Sets the CSS styles for outer part. 777 | * @param array $value list of styles 778 | * @since 1.1 779 | */ 780 | public function setOuterStyle($value) 781 | { 782 | $this->setStyle(0, $value); 783 | } 784 | 785 | /** 786 | * Sets the CSS styles for button part. 787 | * @param array $value list of styles 788 | * @since 1.1 789 | */ 790 | public function setButtonStyle($value) 791 | { 792 | $this->setStyle(2, $value); 793 | } 794 | 795 | /** 796 | * Sets custom user's view path. 797 | * @param string $value view path 798 | * Since 1.1 this method is public. 799 | */ 800 | public function setCookieView($value) 801 | { 802 | $value = trim($value); 803 | if (!empty($value)) { 804 | $this->cookieView = $value; 805 | } 806 | } 807 | 808 | /** 809 | * @return array 810 | * @since 1.1 811 | */ 812 | public function getButtonHtml() 813 | { 814 | return $this->buttonHtml; 815 | } 816 | 817 | /** 818 | * @return array 819 | * @since 1.1 820 | */ 821 | public function getButtonStyle() 822 | { 823 | return $this->buttonStyle; 824 | } 825 | 826 | /** 827 | * @return array 828 | * @since 1.1 829 | */ 830 | public function getClassOptions() 831 | { 832 | return $this->classOptions; 833 | } 834 | 835 | /** 836 | * @return array 837 | * @since 1.1 838 | */ 839 | public function getContentOptions() 840 | { 841 | return $this->contentOptions; 842 | } 843 | 844 | /** 845 | * @return array 846 | * @since 1.1 847 | */ 848 | public function getCookieOptions() 849 | { 850 | return $this->cookieOptions; 851 | } 852 | 853 | /** 854 | * @return string 855 | * @since 1.1 856 | */ 857 | public function getCookieView() 858 | { 859 | return $this->cookieView; 860 | } 861 | 862 | /** 863 | * @return array 864 | * @since 1.1 865 | */ 866 | public function getInnerHtml() 867 | { 868 | return $this->innerHtml; 869 | } 870 | 871 | /** 872 | * @return array 873 | * @since 1.1 874 | */ 875 | public function getInnerStyle() 876 | { 877 | return $this->innerStyle; 878 | } 879 | 880 | /** 881 | * @return array 882 | * @since 1.1 883 | */ 884 | public function getOuterHtml() 885 | { 886 | return $this->outerHtml; 887 | } 888 | 889 | /** 890 | * @return array 891 | * @since 1.1 892 | */ 893 | public function getOuterStyle() 894 | { 895 | return $this->outerStyle; 896 | } 897 | } 898 | -------------------------------------------------------------------------------- /src/assets/CookieMonsterAsset.php: -------------------------------------------------------------------------------- 1 | js[] = 'CookieMonster' . (YII_DEBUG ? '' : '.min') . '.js'; 22 | parent::init(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/js/CookieMonster.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * CookieMonster v1.1.0 3 | * Paweł Bizley Brzozowski 4 | * https://github.com/bizley/yii2-cookiemonster 5 | */ 6 | let CookieMonster = { 7 | init: function(options) { 8 | if (options === undefined) { 9 | options = {}; 10 | } 11 | this.options(options); 12 | this.monit = jQuery("." + this.classOuter); 13 | this.button = this.monit.find("." + this.classButton); 14 | this.checkCookie(); 15 | }, 16 | defaults: { 17 | classOuter: "CookieMonsterBox", 18 | classButton: "CookieMonsterOk", 19 | domain: null, 20 | maxAge: null, 21 | expires: 30, 22 | name: "CookieMonsterAgreed", 23 | path: "/", 24 | secure: false, 25 | value: "true", 26 | sameSite: "lax" 27 | }, 28 | options: function(options) { 29 | this.classOuter = options.classOuter || this.defaults.classOuter; 30 | this.classButton = options.classButton || this.defaults.classButton; 31 | this.domain = options.domain || this.defaults.domain; 32 | this.maxAge = options.maxAge || this.defaults.maxAge; 33 | this.expires = options.expires || this.defaults.expires; 34 | this.name = this.defaults.name; 35 | this.secure = options.secure || this.defaults.secure; 36 | this.value = this.defaults.value; 37 | this.sameSite = options.sameSite || this.defaults.sameSite; 38 | }, 39 | agree: function(e) { 40 | e.preventDefault(); 41 | this.createCookie(); 42 | this.hideMonit(); 43 | }, 44 | bind: function() { 45 | this.button.on("click", jQuery.proxy(this.agree, this)); 46 | }, 47 | checkCookie: function() { 48 | if (this.readCookie() !== this.value) { 49 | this.showMonit(); 50 | } 51 | }, 52 | createCookie: function() { 53 | document.cookie = this.name 54 | + "=" 55 | + this.value 56 | + this.setExpires() 57 | + this.setPath() 58 | + this.setDomain() 59 | + this.setMaxAge() 60 | + this.setSecure() 61 | + this.setSameSite(); 62 | }, 63 | hideMonit: function() { 64 | this.monit.remove(); 65 | }, 66 | readCookie: function() { 67 | let cookie = document.cookie.split(";"); 68 | for (let i = 0; i < cookie.length; i++) { 69 | let cookieElement = cookie[i]; 70 | while (cookieElement.charAt(0) === " ") { 71 | cookieElement = cookieElement.substring(1, cookieElement.length); 72 | } 73 | if (cookieElement.indexOf(this.name + "=") === 0) { 74 | return cookieElement.substring(this.name.length + 1, cookieElement.length); 75 | } 76 | } 77 | return null; 78 | }, 79 | setDomain: function() { 80 | if (this.domain) { 81 | return "; domain=" + encodeURIComponent(this.domain); 82 | } 83 | return ""; 84 | }, 85 | setExpires: function() { 86 | if (this.expires) { 87 | let date = new Date(); 88 | date.setTime(date.getTime() + (this.expires * 24 * 60 * 60 * 1000)); 89 | return "; expires=" + date.toGMTString(); 90 | } 91 | return ""; 92 | }, 93 | setMaxAge: function() { 94 | if (this.maxAge) { 95 | return "; max-age=" + this.maxAge; 96 | } 97 | return ""; 98 | }, 99 | setPath: function() { 100 | return "; path=" + (this.path ? this.path : "/"); 101 | }, 102 | setSecure: function() { 103 | if (this.secure) { 104 | return "; secure"; 105 | } 106 | return ""; 107 | }, 108 | setSameSite: function() { 109 | return "; sameSite=" + this.sameSite; 110 | }, 111 | showMonit: function() { 112 | this.monit.css("display", "block"); 113 | this.bind(); 114 | } 115 | }; 116 | -------------------------------------------------------------------------------- /src/js/CookieMonster.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * CookieMonster v1.1.0 3 | * Paweł Bizley Brzozowski 4 | * https://github.com/bizley/yii2-cookiemonster 5 | */ 6 | let CookieMonster={init:function(t){void 0===t&&(t={}),this.options(t),this.monit=jQuery("."+this.classOuter),this.button=this.monit.find("."+this.classButton),this.checkCookie()},defaults:{classOuter:"CookieMonsterBox",classButton:"CookieMonsterOk",domain:null,maxAge:null,expires:30,name:"CookieMonsterAgreed",path:"/",secure:!1,value:"true",sameSite:"lax"},options:function(t){this.classOuter=t.classOuter||this.defaults.classOuter,this.classButton=t.classButton||this.defaults.classButton,this.domain=t.domain||this.defaults.domain,this.maxAge=t.maxAge||this.defaults.maxAge,this.expires=t.expires||this.defaults.expires,this.name=this.defaults.name,this.secure=t.secure||this.defaults.secure,this.value=this.defaults.value,this.sameSite=t.sameSite||this.defaults.sameSite},agree:function(t){t.preventDefault(),this.createCookie(),this.hideMonit()},bind:function(){this.button.on("click",jQuery.proxy(this.agree,this))},checkCookie:function(){this.readCookie()!==this.value&&this.showMonit()},createCookie:function(){document.cookie=this.name+"="+this.value+this.setExpires()+this.setPath()+this.setDomain()+this.setMaxAge()+this.setSecure()+this.setSameSite()},hideMonit:function(){this.monit.remove()},readCookie:function(){let t=document.cookie.split(";");for(let e=0;e