Merge remote-tracking branch 'consent-banner/master' into consent-control-lib
Merge with consent-banner in Azure and solve the conflicts
This commit is contained in:
Коммит
6899e3e4e7
|
@ -44,6 +44,12 @@ jspm_packages/
|
|||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Host html file
|
||||
!dist/index.html
|
||||
|
||||
# TypeScript v2 declaration files
|
||||
!dist/consent-banner.d.ts
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
|
@ -102,3 +108,12 @@ dist
|
|||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
|
221
README.md
221
README.md
|
@ -1,5 +1,224 @@
|
|||
# Consent Banner
|
||||
|
||||
# Contributing
|
||||
## Overview
|
||||
|
||||
Consent banner is the library which will generate a banner at the specified position for asking the cookie preferences.
|
||||
|
||||
It contains two buttons, `accept all` and `more info`. If the user clicks `more info` button, A dialog will pop up so that the user can set the cookie categories that he/she wants to share with us.
|
||||
|
||||
## Building and running on localhost
|
||||
|
||||
First install dependencies:
|
||||
|
||||
```sh
|
||||
npm i
|
||||
```
|
||||
|
||||
To create a production build:
|
||||
|
||||
```sh
|
||||
npm run build-prod
|
||||
```
|
||||
|
||||
To create a development build:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
```sh
|
||||
npm run start
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```sh
|
||||
npm run test
|
||||
```
|
||||
|
||||
## Example use
|
||||
|
||||
This is part of your `html` page.
|
||||
|
||||
```HTML
|
||||
<body>
|
||||
...
|
||||
<div id="app"></div>
|
||||
...
|
||||
</body>
|
||||
```
|
||||
|
||||
If you want to insert a banner into the `<div id="app"></div>`, you can use the following example.
|
||||
|
||||
```TypeScript
|
||||
|
||||
let cookieCategories: ICookieCategory[] =
|
||||
[
|
||||
{
|
||||
id: "c0",
|
||||
name: "1. Essential cookies",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>.",
|
||||
isUnswitchable: true
|
||||
},
|
||||
{
|
||||
id: "c1",
|
||||
name: "2. Performance & analytics",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>."
|
||||
},
|
||||
{
|
||||
id: "c2",
|
||||
name: "3. Advertising/Marketing",
|
||||
descHtml: "Blah"
|
||||
},
|
||||
{
|
||||
id: "c3",
|
||||
name: "4. Targeting/personalization",
|
||||
descHtml: "Blah"
|
||||
}
|
||||
];
|
||||
|
||||
let textResources: ITextResources = {
|
||||
bannerMessageHtml = "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel = "Accept all",
|
||||
moreInfoLabel = "More info",
|
||||
preferencesDialogCloseLabel = "Close",
|
||||
preferencesDialogTitle = "Manage cookie preferences",
|
||||
preferencesDialogDescHtml = "Most Microsoft sites...",
|
||||
acceptLabel = "Accept",
|
||||
rejectLabel = "Reject",
|
||||
saveLabel = "Save changes",
|
||||
resetLabel = "Reset all"
|
||||
};
|
||||
|
||||
let callBack = function(obj: any) { console.log(obj); };
|
||||
|
||||
let cc = new ConsentControl("app", "en", callBack, cookieCategories, textResources);
|
||||
let cookieCategoriePreferences: ICookieCategoriesPreferences = { "c1": undefined, "c2": false, "c3": true };
|
||||
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
```
|
||||
|
||||
## Developer Guide
|
||||
|
||||
`ConsentControl` consists of 2 main elements: **Banner** and **Preferences Dialog**. Use `containerElementOrId`, `culture`, `onPreferencesChanged`, `cookieCategories`, `textResources` to create an instance. `culture` will be used to determine the direction of the banner and preferences dialog.
|
||||
|
||||
```JavaScript
|
||||
var cc = new ConsentControl(
|
||||
containerElementOrId: string | HTMLElement, // here the banner will be inserted, can be HTMLElement or element id
|
||||
culture: string, // culture can be just language "en" or language-country "en-us". Based on language RTL should be applied (https://www.w3.org/International/questions/qa-scripts.en)
|
||||
onPreferencesChanged: (cookieCategoriesPreferences: ICookieCategoriesPreferences) => void, // callback function, called on preferences changes (via "Accept All" or "Save changes"), must pass cookieCategoriePreferences, see ICookieCategoriesPreferences in Data types
|
||||
cookieCategories?: ICookieCategory[], // optional, see ICookieCategory in Data types
|
||||
textResources?: ITextResources // optional, see ITextResources in Data types
|
||||
);
|
||||
```
|
||||
|
||||
1. `setTextResources(textResources: ITextResources)` can be used to set the texts.
|
||||
|
||||
2. `setContainerElement(containerElementOrId: string | HTMLElement)` can be used to set the container element for the banner and preferences dialog.
|
||||
|
||||
If you pass `HTMLElement`, it will be used as the container. If you pass `string`, the method will use it as the `id` to find the container element.
|
||||
|
||||
```JavaScript
|
||||
cc.setContainerElement("app");
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```JavaScript
|
||||
let container = document.getElementById('app');
|
||||
cc.setContainerElement(container);
|
||||
```
|
||||
|
||||
If the container can not be found, it will throw an error. `new Error("Container not found error")`
|
||||
|
||||
3. `getContainerElement()` will return the current container element.
|
||||
|
||||
4. You can set the direction manually by using `setDirection(dir?: string)`. `dir` can be `"ltr"` or `"rtl"`. If `dir` is not passed, it will determine the direction by `dir` attribute in `html`, `body` or `culture`.
|
||||
|
||||
```JavaScript
|
||||
// There are 3 cases. dir="rtl", dir="ltr", empty
|
||||
|
||||
// Set direction to rtl (right-to-left)
|
||||
cc.setDirection("rtl");
|
||||
|
||||
// Set direction to ltr (left-to-right)
|
||||
cc.setDirection("ltr");
|
||||
|
||||
// It will use "dir" attribute in "html" or "body"
|
||||
// If the "dir" attribute is not specified, it will apply the direction based on "culture"
|
||||
cc.setDirection();
|
||||
```
|
||||
|
||||
5. `getDirection()` will return the current direction.
|
||||
|
||||
### Data types
|
||||
|
||||
There are three data types: `ICookieCategory`, `ITextResources` and `ICookieCategoriesPreferences`.
|
||||
|
||||
+ `ICookieCategory` is used to create cookie categories that will be showed in the preferences dialog.
|
||||
+ `ITextResources` is the texts that will be used in the banner and preferences dialog.
|
||||
+ `ICookieCategoriesPreferences` is used to store the preferences in each cookie categories.
|
||||
|
||||
```TypeScript
|
||||
// All categories should be replaced with the passed ones in the control
|
||||
interface ICookieCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
descHtml: string;
|
||||
isUnswitchable?: boolean; // optional, prevents toggling the category. True only for categories like Essential cookies.
|
||||
}
|
||||
|
||||
// only the passed text resources should be replaced in the control. If any string is not passed the control should keep the default value
|
||||
interface ITextResources {
|
||||
bannerMessageHtml?: string;
|
||||
acceptAllLabel?: string;
|
||||
moreInfoLabel?: string;
|
||||
preferencesDialogCloseLabel?: string;
|
||||
preferencesDialogTitle?: string;
|
||||
preferencesDialogDescHtml?: string;
|
||||
acceptLabel?: string;
|
||||
rejectLabel?: string;
|
||||
saveLabel?: string;
|
||||
resetLabel?: string;
|
||||
}
|
||||
|
||||
interface ICookieCategoriesPreferences {
|
||||
[key: string]: boolean | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
### Provided methods
|
||||
|
||||
+ Methods related to **banner**: `showBanner(cookieCategoriesPreferences: ICookieCategoriesPreferences)` and `hideBanner()`
|
||||
+ Methods related to **Preferences Dialog**: `showPreferences(cookieCategoriesPreferences: ICookieCategoriesPreferences)` and `hidePreferences()`
|
||||
|
||||
```JavaScript
|
||||
// Insert all necessary HTML code and shows the banner. Until this method is called there should be no HTML elements of the Consent Control anywhere in the DOM. Only one banner will be created. If call it many times, it will only display the last one and remove all previous banners.
|
||||
cc.showBanner(
|
||||
cookieCategoriesPreferences: ICookieCategoriesPreferences // see ICookieCategoriesPreferences in Data types
|
||||
);
|
||||
|
||||
// Hides the banner and the Preferences Dialog. Removes all HTML elements of the Consent Control from the DOM
|
||||
cc.hideBanner();
|
||||
|
||||
// Shows Preferences Dialog. Leaves banner state unchanged. If there is a preferences dialog, it will show the dialog instead of creating a new one.
|
||||
cc.showPreferences(
|
||||
cookieCategoriesPreferences: ICookieCategoriesPreferences // see ICookieCategoriesPreferences in Data types
|
||||
);
|
||||
|
||||
// Hides Preferences Dialog. Removes all HTML elements of the Preferences Dialog from the DOM. Leaves banner state unchanged
|
||||
cc.hidePreferences();
|
||||
```
|
||||
|
||||
### Custom settings
|
||||
|
||||
1. Change the width of buttons in banner: Change `$bannerBtnWidth` in `styles.scss`
|
||||
|
||||
2. `webpack.config.js` file is for development purpose, and `webpack.production.config.js` is for production. The only difference between `webpack.config.js` and `webpack.production.config.js` is `localIdentName` in `use/options/modules` under `module/rules`.
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Node.js
|
||||
# Build a general Node.js project with npm.
|
||||
# Add steps that analyze code, save build artifacts, deploy, and more:
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
|
||||
|
||||
trigger:
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '12.x'
|
||||
displayName: 'Install Node.js'
|
||||
|
||||
- script: |
|
||||
npm install
|
||||
npm run build-prod
|
||||
npm run lint
|
||||
npm run test-ci
|
||||
displayName: 'npm install and build'
|
|
@ -0,0 +1,101 @@
|
|||
declare interface ICookieCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
descHtml: string;
|
||||
isUnswitchable?: boolean;
|
||||
}
|
||||
declare interface ITextResources {
|
||||
bannerMessageHtml?: string;
|
||||
acceptAllLabel?: string;
|
||||
moreInfoLabel?: string;
|
||||
preferencesDialogCloseLabel?: string;
|
||||
preferencesDialogTitle?: string;
|
||||
preferencesDialogDescHtml?: string;
|
||||
acceptLabel?: string;
|
||||
rejectLabel?: string;
|
||||
saveLabel?: string;
|
||||
resetLabel?: string;
|
||||
}
|
||||
declare interface ICookieCategoriesPreferences {
|
||||
[key: string]: boolean | undefined;
|
||||
}
|
||||
|
||||
declare class PreferencesControl { }
|
||||
|
||||
export declare class ConsentControl {
|
||||
private containerElement;
|
||||
culture: string;
|
||||
onPreferencesChanged: (cookieCategoriesPreferences: ICookieCategoriesPreferences) => void;
|
||||
cookieCategories: ICookieCategory[];
|
||||
textResources: ITextResources;
|
||||
preferencesCtrl: PreferencesControl | null;
|
||||
private direction;
|
||||
defaultCookieCategories: ICookieCategory[];
|
||||
defaultTextResources: ITextResources;
|
||||
constructor(containerElementOrId: string | HTMLElement, culture: string, onPreferencesChanged: (cookieCategoriesPreferences: ICookieCategoriesPreferences) => void, cookieCategories?: ICookieCategory[], textResources?: ITextResources);
|
||||
/**
|
||||
* Set the text resources for the banner to display the text in each area
|
||||
*
|
||||
* @param {ITextResources} textResources the text want to be displayed
|
||||
*/
|
||||
setTextResources(textResources: ITextResources): void;
|
||||
/**
|
||||
* Insert all necessary HTML code and shows the banner.
|
||||
* Until this method is called there should be no HTML elements of the Consent Control anywhere in the DOM
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
showBanner(cookieCategoriesPreferences: ICookieCategoriesPreferences): void;
|
||||
/**
|
||||
* Hides the banner and the Preferences Dialog.
|
||||
* Removes all HTML elements of the Consent Control from the DOM
|
||||
*/
|
||||
hideBanner(): void;
|
||||
/**
|
||||
* Shows Preferences Dialog. Leaves banner state unchanged
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
showPreferences(cookieCategoriesPreferences: ICookieCategoriesPreferences): void;
|
||||
/**
|
||||
* Hides Preferences Dialog.
|
||||
* Removes all HTML elements of the Preferences Dialog from the DOM. Leaves banner state unchanged
|
||||
*/
|
||||
hidePreferences(): void;
|
||||
/**
|
||||
* The method is used to initialize the preferences dialog.
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
private initPreferencesCtrl;
|
||||
/**
|
||||
* Function that will be called when "Accept all" button is clicked
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
private onAcceptAllClicked;
|
||||
/**
|
||||
* Function that is used to set preferencesCtrl property to null
|
||||
*/
|
||||
private onPreferencesClosed;
|
||||
/**
|
||||
* Set the container that will be used for the banner
|
||||
*
|
||||
* @param {string | HTMLElement} containerElementOrId here the banner will be inserted
|
||||
*/
|
||||
setContainerElement(containerElementOrId: string | HTMLElement): void;
|
||||
/**
|
||||
* Return the container that is used for the banner
|
||||
*/
|
||||
getContainerElement(): HTMLElement | null;
|
||||
/**
|
||||
* Set the direction by passing the parameter or by checking the culture property
|
||||
*
|
||||
* @param {string} dir direction for the web, ltr or rtl
|
||||
*/
|
||||
setDirection(dir?: string): void;
|
||||
/**
|
||||
* Return the direction
|
||||
*/
|
||||
getDirection(): string;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Test page</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<h1>aaabcdef</h1>
|
||||
<script src="consent-banner.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
// For a detailed explanation regarding each configuration property, visit:
|
||||
// https://jestjs.io/docs/en/configuration.html
|
||||
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
collectCoverageFrom: [
|
||||
"src/**/*.{js,jsx,ts,tsx}",
|
||||
"!*.d.ts"
|
||||
],
|
||||
coverageReporters: [
|
||||
"html"
|
||||
],
|
||||
moduleNameMapper: {
|
||||
"^.+\\.(css|scss)$": "identity-obj-proxy"
|
||||
},
|
||||
resolver: "jest-pnp-resolver",
|
||||
testMatch: [
|
||||
"<rootDir>/src/**/*.test.ts?(x)"
|
||||
],
|
||||
testEnvironment: "jsdom",
|
||||
testURL: "http://localhost",
|
||||
transform: {
|
||||
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest",
|
||||
},
|
||||
transformIgnorePatterns: [
|
||||
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$"
|
||||
],
|
||||
testPathIgnorePatterns: [
|
||||
],
|
||||
//testResultsProcessor: "<rootDir>/node_modules/jest-junit-reporter",
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "consent-banner",
|
||||
"version": "2.0.0",
|
||||
"description": "The library which will generate a banner at the specified position for asking the cookie preferences.",
|
||||
"main": "index.js",
|
||||
"types": "dist/consent-banner.d.ts",
|
||||
"keywords": [
|
||||
"cookie preferences",
|
||||
"banner"
|
||||
],
|
||||
"author": "Microsoft",
|
||||
"license": "MIT",
|
||||
"files": [ "dist/consent-banner.js", "dist/consent-banner.d.ts" ],
|
||||
"scripts": {
|
||||
"prepare": "npm run build-prod",
|
||||
"build": "webpack -d --mode development",
|
||||
"build-prod": "webpack -p --mode production --config ./webpack.production.config.js",
|
||||
"start": "webpack-dev-server --open",
|
||||
"test": "jest --watchAll",
|
||||
"test-coverage": "jest --coverage",
|
||||
"test-ci": "jest",
|
||||
"lint": "tslint -p tsconfig.json -t stylish"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/node-sass": "^4.11.0",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"css-loader": "^3.5.2",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^25.3.0",
|
||||
"jest-junit-reporter": "^1.1.0",
|
||||
"jest-pnp-resolver": "^1.2.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"style-loader": "^1.1.4",
|
||||
"ts-jest": "^25.3.1",
|
||||
"tslint": "^6.1.1",
|
||||
"tslint-microsoft-contrib": "^6.2.0",
|
||||
"typescript": "^3.8.3",
|
||||
"webpack": "^4.42.1",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3"
|
||||
},
|
||||
"jest": {
|
||||
"moduleNameMapper": {
|
||||
"\\.(s?css|less)$": "identity-obj-proxy"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not ie <= 9",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
declare module "*.scss";
|
|
@ -0,0 +1,14 @@
|
|||
export class HtmlTools {
|
||||
public static escapeHtml(s: string | undefined): string {
|
||||
if (s) {
|
||||
return s.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
import { ConsentControl } from "./index";
|
||||
import * as styles from "./styles.scss";
|
||||
|
||||
describe("Test radio buttons and 'Reset all' button", () => {
|
||||
let testId: string = "app";
|
||||
|
||||
function testRadioBtnState(radioButtons: String[]): void {
|
||||
let cookieItemRadioBtn: HTMLInputElement[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
for (let i = 0; i < radioButtons.length; i++) {
|
||||
if (radioButtons[i] === "checked") {
|
||||
expect(cookieItemRadioBtn[i].checked).toBeTruthy();
|
||||
}
|
||||
else {
|
||||
expect(cookieItemRadioBtn[i].checked).toBeFalsy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Click 'More info' button and then click radio buttons. All cookieCategoriePreferences will be reset to undefined when 'Reset all' is clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": undefined, "c3": false };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
let cookieInfo = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[1];
|
||||
cookieInfo.click();
|
||||
|
||||
expect(cc.preferencesCtrl).toBeTruthy();
|
||||
let cookieModal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
expect(cookieModal.style.display).toBe("block");
|
||||
|
||||
let cookieItemRadioBtn: HTMLInputElement[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
cookieItemRadioBtn[1].click();
|
||||
cookieItemRadioBtn[2].click();
|
||||
cookieItemRadioBtn[4].click();
|
||||
|
||||
testRadioBtnState(["unchecked", "checked", "checked", "unchecked", "checked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": false, "c2": true, "c3": true });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
|
||||
let resetAllBtn = <HTMLElement> document.getElementsByClassName(styles.modalButtonReset)[0];
|
||||
resetAllBtn.click();
|
||||
|
||||
testRadioBtnState(["unchecked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": undefined, "c2": undefined, "c3": undefined });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
});
|
||||
|
||||
test("Call showPreferences(...) and then click radio buttons. All cookieCategoriePreferences will be reset to undefined when 'Reset all' is clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
expect(cc.preferencesCtrl).toBeTruthy();
|
||||
let cookieModal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
expect(cookieModal.style.display).toBe("block");
|
||||
|
||||
let cookieItemRadioBtn: HTMLInputElement[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
cookieItemRadioBtn[1].click();
|
||||
cookieItemRadioBtn[2].click();
|
||||
cookieItemRadioBtn[4].click();
|
||||
|
||||
testRadioBtnState(["unchecked", "checked", "checked", "unchecked", "checked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": false, "c2": true, "c3": true });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
|
||||
let resetAllBtn = <HTMLElement> document.getElementsByClassName(styles.modalButtonReset)[0];
|
||||
resetAllBtn.click();
|
||||
|
||||
testRadioBtnState(["unchecked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": undefined, "c2": undefined, "c3": undefined });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
});
|
||||
|
||||
test("Call showPreferences(...) with unswitchable id and click radio buttons. All cookiePreferences will be reset to undefined when 'Reset all' is clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c0": true, "c1": true, "c2": false, "c3": undefined };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
expect(cc.preferencesCtrl).toBeTruthy();
|
||||
let cookieModal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
expect(cookieModal.style.display).toBe("block");
|
||||
|
||||
let cookieItemRadioBtn: HTMLInputElement[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
cookieItemRadioBtn[1].click();
|
||||
cookieItemRadioBtn[2].click();
|
||||
cookieItemRadioBtn[4].click();
|
||||
|
||||
testRadioBtnState(["unchecked", "checked", "checked", "unchecked", "checked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c0": true, "c1": false, "c2": true, "c3": true });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
|
||||
let resetAllBtn = <HTMLElement> document.getElementsByClassName(styles.modalButtonReset)[0];
|
||||
resetAllBtn.click();
|
||||
|
||||
testRadioBtnState(["unchecked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c0": true, "c1": undefined, "c2": undefined, "c3": undefined });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
});
|
||||
|
||||
test("Click 'More info' button and then click radio buttons. cookieCategoriePreferences will be set", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": undefined, "c3": false };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
let cookieInfo = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[1];
|
||||
cookieInfo.click();
|
||||
|
||||
expect(cc.preferencesCtrl).toBeTruthy();
|
||||
let cookieModal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
expect(cookieModal.style.display).toBe("block");
|
||||
|
||||
let cookieItemRadioBtn: HTMLInputElement[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
cookieItemRadioBtn[0].click();
|
||||
cookieItemRadioBtn[3].click();
|
||||
cookieItemRadioBtn[5].click();
|
||||
|
||||
testRadioBtnState(["checked", "unchecked", "unchecked", "checked", "unchecked", "checked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": true, "c2": false, "c3": false });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
|
||||
cookieItemRadioBtn[1].click();
|
||||
cookieItemRadioBtn[2].click();
|
||||
cookieItemRadioBtn[4].click();
|
||||
|
||||
testRadioBtnState(["unchecked", "checked", "checked", "unchecked", "checked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": false, "c2": true, "c3": true });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
});
|
||||
|
||||
test("Call showPreferences(...) and then click radio buttons. cookieCategoriePreferences will be set", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
expect(cc.preferencesCtrl).toBeTruthy();
|
||||
let cookieModal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
expect(cookieModal.style.display).toBe("block");
|
||||
|
||||
let cookieItemRadioBtn: HTMLInputElement[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
cookieItemRadioBtn[0].click();
|
||||
cookieItemRadioBtn[3].click();
|
||||
cookieItemRadioBtn[5].click();
|
||||
|
||||
testRadioBtnState(["checked", "unchecked", "unchecked", "checked", "unchecked", "checked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": true, "c2": false, "c3": false });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
|
||||
cookieItemRadioBtn[1].click();
|
||||
cookieItemRadioBtn[2].click();
|
||||
cookieItemRadioBtn[4].click();
|
||||
|
||||
testRadioBtnState(["unchecked", "checked", "checked", "unchecked", "checked", "unchecked"]);
|
||||
|
||||
if (cc.preferencesCtrl) {
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual({ "c1": false, "c2": true, "c3": true });
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences).toEqual(cookieCategoriePreferences);
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test 'Accept all' button", () => {
|
||||
let testId: string = "app";
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Click 'Accept all' button and all cookieCategoriePreferences will be set to 'true'", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c2": undefined, "c3": false };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
let acceptAllBtn = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[0];
|
||||
acceptAllBtn.click();
|
||||
|
||||
for (let cookieCategory of cc.cookieCategories) {
|
||||
if (!cookieCategory.isUnswitchable) {
|
||||
if (cc.preferencesCtrl) {
|
||||
let id = cookieCategory.id;
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences[id]).toBeTruthy();
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Initialize cookieCategoriesPreferences with unswitchable id and click 'Accept all' button. All cookieCategoriePreferences will be set to 'true'", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c0": true, "c2": undefined, "c3": false };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
let acceptAllBtn = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[0];
|
||||
acceptAllBtn.click();
|
||||
|
||||
for (let cookieCategory of cc.cookieCategories) {
|
||||
if (!cookieCategory.isUnswitchable) {
|
||||
if (cc.preferencesCtrl) {
|
||||
let id = cookieCategory.id;
|
||||
expect(cc.preferencesCtrl.cookieCategoriesPreferences[id]).toBeTruthy();
|
||||
}
|
||||
else {
|
||||
throw new Error("Preference dialog not found error");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,587 @@
|
|||
import { ConsentControl } from "./index";
|
||||
|
||||
describe("Test constructor", () => {
|
||||
let testId: string = "app";
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("CookieCategories and textResources full provided", () => {
|
||||
let cookieCategories = [
|
||||
{
|
||||
id: "cookie1",
|
||||
name: "Test cookie1",
|
||||
descHtml: "This is for test cookie1"
|
||||
},
|
||||
{
|
||||
id: "cookie2",
|
||||
name: "Test cookie2",
|
||||
descHtml: "This is for test cookie2 with 4th property",
|
||||
isUnswitchable: true
|
||||
}
|
||||
];
|
||||
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, cookieCategories, textResources);
|
||||
|
||||
expect(cc.culture).toBe("en");
|
||||
expect(cc.cookieCategories).toEqual(cookieCategories);
|
||||
expect(cc.textResources).toEqual(textResources);
|
||||
});
|
||||
|
||||
test("No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
expect(cc.culture).toBe("en");
|
||||
expect(cc.cookieCategories).toEqual([
|
||||
{
|
||||
id: "c0",
|
||||
name: "1. Essential cookies",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>.",
|
||||
isUnswitchable: true
|
||||
},
|
||||
{
|
||||
id: "c1",
|
||||
name: "2. Performance & analytics",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>."
|
||||
},
|
||||
{
|
||||
id: "c2",
|
||||
name: "3. Advertising/Marketing",
|
||||
descHtml: "Blah"
|
||||
},
|
||||
{
|
||||
id: "c3",
|
||||
name: "4. Targeting/personalization",
|
||||
descHtml: "Blah"
|
||||
}
|
||||
]);
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel: "Accept all",
|
||||
moreInfoLabel: "More info",
|
||||
preferencesDialogCloseLabel: "Close",
|
||||
preferencesDialogTitle: "Manage cookie preferences",
|
||||
preferencesDialogDescHtml: "Most Microsoft sites...",
|
||||
acceptLabel: "Accept",
|
||||
rejectLabel: "Reject",
|
||||
saveLabel: "Save changes",
|
||||
resetLabel: "Reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources full provided", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.culture).toBe("en");
|
||||
expect(cc.cookieCategories).toEqual([
|
||||
{
|
||||
id: "c0",
|
||||
name: "1. Essential cookies",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>.",
|
||||
isUnswitchable: true
|
||||
},
|
||||
{
|
||||
id: "c1",
|
||||
name: "2. Performance & analytics",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>."
|
||||
},
|
||||
{
|
||||
id: "c2",
|
||||
name: "3. Advertising/Marketing",
|
||||
descHtml: "Blah"
|
||||
},
|
||||
{
|
||||
id: "c3",
|
||||
name: "4. Targeting/personalization",
|
||||
descHtml: "Blah"
|
||||
}
|
||||
]);
|
||||
expect(cc.textResources).toEqual(textResources);
|
||||
});
|
||||
|
||||
test("CookieCategories provided, no textResources", () => {
|
||||
let cookieCategories = [
|
||||
{
|
||||
id: "cookie1",
|
||||
name: "Test cookie1",
|
||||
descHtml: "This is for test cookie1"
|
||||
},
|
||||
{
|
||||
id: "cookie2",
|
||||
name: "Test cookie2",
|
||||
descHtml: "This is for test cookie2 with 4th property",
|
||||
isUnswitchable: true
|
||||
}
|
||||
];
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, cookieCategories);
|
||||
|
||||
expect(cc.culture).toBe("en");
|
||||
expect(cc.cookieCategories).toEqual(cookieCategories);
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel: "Accept all",
|
||||
moreInfoLabel: "More info",
|
||||
preferencesDialogCloseLabel: "Close",
|
||||
preferencesDialogTitle: "Manage cookie preferences",
|
||||
preferencesDialogDescHtml: "Most Microsoft sites...",
|
||||
acceptLabel: "Accept",
|
||||
rejectLabel: "Reject",
|
||||
saveLabel: "Save changes",
|
||||
resetLabel: "Reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without bannerMessageHtml", () => {
|
||||
let textResources = {
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.culture).toBe("en");
|
||||
expect(cc.cookieCategories).toEqual([
|
||||
{
|
||||
id: "c0",
|
||||
name: "1. Essential cookies",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>.",
|
||||
isUnswitchable: true
|
||||
},
|
||||
{
|
||||
id: "c1",
|
||||
name: "2. Performance & analytics",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>."
|
||||
},
|
||||
{
|
||||
id: "c2",
|
||||
name: "3. Advertising/Marketing",
|
||||
descHtml: "Blah"
|
||||
},
|
||||
{
|
||||
id: "c3",
|
||||
name: "4. Targeting/personalization",
|
||||
descHtml: "Blah"
|
||||
}
|
||||
]);
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without acceptAllLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "Accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without moreInfoLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "More info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without preferencesDialogCloseLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without preferencesDialogTitle", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "Manage cookie preferences",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without preferencesDialogDescHtml", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "Most Microsoft sites...",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without acceptLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "Accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without rejectLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "Reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without saveLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "Save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without resetLabel", () => {
|
||||
let textResources = {
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "This is banner message.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "Reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without bannerMessageHtml, acceptAllLabel", () => {
|
||||
let textResources = {
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.culture).toBe("en");
|
||||
expect(cc.cookieCategories).toEqual([
|
||||
{
|
||||
id: "c0",
|
||||
name: "1. Essential cookies",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>.",
|
||||
isUnswitchable: true
|
||||
},
|
||||
{
|
||||
id: "c1",
|
||||
name: "2. Performance & analytics",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>."
|
||||
},
|
||||
{
|
||||
id: "c2",
|
||||
name: "3. Advertising/Marketing",
|
||||
descHtml: "Blah"
|
||||
},
|
||||
{
|
||||
id: "c3",
|
||||
name: "4. Targeting/personalization",
|
||||
descHtml: "Blah"
|
||||
}
|
||||
]);
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel: "Accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "This is reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
|
||||
test("No cookieCategories, textResources without bannerMessageHtml, rejectLabel", () => {
|
||||
let textResources = {
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
};
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack, undefined, textResources);
|
||||
|
||||
expect(cc.textResources).toEqual({
|
||||
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel: "This is accept all",
|
||||
moreInfoLabel: "This is more info",
|
||||
preferencesDialogCloseLabel: "This is Close",
|
||||
preferencesDialogTitle: "This is preferences dialog title",
|
||||
preferencesDialogDescHtml: "This is preferences dialog text",
|
||||
acceptLabel: "This is accept",
|
||||
rejectLabel: "Reject",
|
||||
saveLabel: "This is save changes",
|
||||
resetLabel: "This is reset all"
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,200 @@
|
|||
import { ConsentControl } from "./index";
|
||||
|
||||
describe("Test language direction", () => {
|
||||
let testId: string = "app";
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Language is ms (ltr). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ms", callBack);
|
||||
expect(cc.getDirection()).toBe("ltr");
|
||||
});
|
||||
|
||||
test("Language is ms (ltr). Set direction to rtl. No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ms", callBack);
|
||||
cc.setDirection("rtl");
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ar (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ar", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is he (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "he", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ps (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ps", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ur (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ur", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is fa (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "fa", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is pa (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "pa", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is sd (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "sd", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is tk (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "tk", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ug (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ug", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is yi (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "yi", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is syr (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "syr", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ks-arab (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ks-arab", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is en-US (ltr). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en-US", callBack);
|
||||
expect(cc.getDirection()).toBe("ltr");
|
||||
});
|
||||
|
||||
test("Language is ar-SA (rtl). No cookieCategories, no textResources", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ar-SA", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test html and body direction", () => {
|
||||
let testId: string = "app";
|
||||
|
||||
let htmlDir: string | null;
|
||||
let bodyDir: string | null;
|
||||
|
||||
beforeAll(() => {
|
||||
htmlDir = document.getElementsByTagName("html")[0].getAttribute("dir");
|
||||
bodyDir = document.getElementsByTagName("body")[0].getAttribute("dir");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (htmlDir) {
|
||||
document.getElementsByTagName("html")[0].setAttribute("dir", htmlDir);
|
||||
}
|
||||
else {
|
||||
document.getElementsByTagName("html")[0].removeAttribute("dir");
|
||||
}
|
||||
|
||||
if (bodyDir) {
|
||||
document.getElementsByTagName("body")[0].setAttribute("dir", bodyDir);
|
||||
}
|
||||
else {
|
||||
document.getElementsByTagName("body")[0].removeAttribute("dir");
|
||||
}
|
||||
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Language is en (ltr). Html dir is rtl. No cookieCategories, no textResources", () => {
|
||||
document.getElementsByTagName("html")[0].setAttribute("dir", "rtl");
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ar (rtl). Html dir is ltr. No cookieCategories, no textResources", () => {
|
||||
document.getElementsByTagName("html")[0].setAttribute("dir", "ltr");
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ar", callBack);
|
||||
expect(cc.getDirection()).toBe("ltr");
|
||||
});
|
||||
|
||||
test("Language is en (ltr). Body dir is rtl. No cookieCategories, no textResources", () => {
|
||||
document.getElementsByTagName("body")[0].setAttribute("dir", "rtl");
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
expect(cc.getDirection()).toBe("rtl");
|
||||
});
|
||||
|
||||
test("Language is ar (rtl). Body dir is ltr. No cookieCategories, no textResources", () => {
|
||||
document.getElementsByTagName("body")[0].setAttribute("dir", "ltr");
|
||||
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "ar", callBack);
|
||||
expect(cc.getDirection()).toBe("ltr");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,843 @@
|
|||
import { ConsentControl } from "./index";
|
||||
import * as styles from "./styles.scss";
|
||||
import { PreferencesControl } from './preferencesControl';
|
||||
|
||||
import { ICookieCategoriesPreferences } from "./interfaces/CookieCategoriesPreferences";
|
||||
|
||||
function testShowingBanner(dir: string): void {
|
||||
let bannerBody = document.getElementsByClassName(styles.bannerBody);
|
||||
expect(bannerBody).toBeTruthy();
|
||||
expect(bannerBody.length).toBe(1);
|
||||
expect(bannerBody[0].getAttribute("dir")).toBe(dir);
|
||||
|
||||
expect(document.getElementsByClassName(styles.bannerInform).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.infoIcon).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.bannerInformBody).length).toBe(1);
|
||||
|
||||
expect(document.getElementsByClassName(styles.buttonGroup).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.bannerButton).length).toBe(2);
|
||||
}
|
||||
|
||||
function testShowingPreferences(cc: ConsentControl, cookieCategoriePreferences: ICookieCategoriesPreferences, display: string): void {
|
||||
expect(document.getElementsByClassName(styles.cookieModal)).toBeTruthy();
|
||||
|
||||
let cookieModal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
expect(cookieModal.getAttribute("dir")).toBe(cc.getDirection());
|
||||
expect(cookieModal.style.display).toBe(display);
|
||||
|
||||
expect(document.getElementsByClassName(styles.modalContainer).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.closeModalIcon).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.modalBody).length).toBe(1);
|
||||
|
||||
expect(document.getElementsByClassName(styles.modalTitle).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.modalContent).length).toBe(1);
|
||||
|
||||
expect(document.getElementsByClassName(styles.cookieStatement).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.cookieOrderedList).length).toBe(1);
|
||||
|
||||
expect(document.getElementsByClassName(styles.cookieListItem).length).toBe(cc.cookieCategories.length);
|
||||
expect(document.getElementsByClassName(styles.cookieListItemTitle).length).toBe(cc.cookieCategories.length);
|
||||
expect(document.getElementsByClassName(styles.cookieListItemDescription).length).toBe(cc.cookieCategories.length);
|
||||
|
||||
// test:
|
||||
// c1: true => accept radio button should be checked
|
||||
// c2: false => reject radio button should be checked
|
||||
let i = 0;
|
||||
for (let cookieCategory of cc.cookieCategories) {
|
||||
if (!cookieCategory.isUnswitchable) {
|
||||
if (cookieCategoriePreferences.hasOwnProperty(cookieCategory.id)) {
|
||||
if (cookieCategoriePreferences[cookieCategory.id]) {
|
||||
let acceptRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i * 2];
|
||||
expect(acceptRadio.checked).toBeTruthy();
|
||||
}
|
||||
else if (cookieCategoriePreferences[cookieCategory.id] === false) {
|
||||
let rejectRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i * 2 + 1];
|
||||
expect(rejectRadio.checked).toBeTruthy();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
expect(document.getElementsByClassName(styles.cookieListItemGroup).length).toBe(i);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtnGroup).length).toBe(i);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtnCtrl).length).toBe(i * 2);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtn).length).toBe(i * 2);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtnLabel).length).toBe(i * 2);
|
||||
|
||||
expect(document.getElementsByClassName(styles.modalButtonGroup).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.modalButtonSave).length).toBe(1);
|
||||
expect(document.getElementsByClassName(styles.modalButtonReset).length).toBe(1);
|
||||
}
|
||||
|
||||
function testModalSaveButton(i: number, defined: number[]): void {
|
||||
let cookieItemRadioBtn: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
cookieItemRadioBtn.click();
|
||||
|
||||
if (defined.includes(i)) {
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonSave)[0]).disabled).toBeTruthy();
|
||||
}
|
||||
else {
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonSave)[0]).disabled).toBeFalsy();
|
||||
}
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
}
|
||||
|
||||
function testRemovingPreferences(): void {
|
||||
let cookieModal = document.getElementsByClassName(styles.cookieModal);
|
||||
expect(cookieModal.length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.modalContainer).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.closeModalIcon).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.modalBody).length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.modalTitle).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.modalContent).length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.cookieStatement).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieOrderedList).length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.cookieListItem).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieListItemTitle).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieListItemDescription).length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.cookieListItemGroup).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtnGroup).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtnCtrl).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtn).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.cookieItemRadioBtnLabel).length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.modalButtonGroup).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.modalButtonSave).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.modalButtonReset).length).toBe(0);
|
||||
}
|
||||
|
||||
describe("Test show and hide banner", () => {
|
||||
let testId: string = "app";
|
||||
let testElementString = `
|
||||
<div class="${styles.bannerBody}" dir=ltr role="alert">
|
||||
<div class="${styles.bannerInform}">
|
||||
<span class="${styles.infoIcon}" aria-label="Information message"></span> <!-- used for icon -->
|
||||
<p class="${styles.bannerInformBody}">We use </p>
|
||||
</div>
|
||||
|
||||
<div class="${styles.buttonGroup}">
|
||||
<button type="button" class="${styles.bannerButton}">Accept all</button>
|
||||
<button type="button" class="${styles.bannerButton}">More info</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- The Modal -->
|
||||
<div class="${styles.cookieModal}" dir=ltr>
|
||||
<div role="presentation" tabindex="-1"></div>
|
||||
<div role="dialog" aria-modal="true" aria-label="Flow scroll" class="${styles.modalContainer}" tabindex="-1">
|
||||
<button aria-label="Close dialog" class="${styles.closeModalIcon}" tabindex="0">✕</button>
|
||||
<div role="document" class="${styles.modalBody}">
|
||||
<div>
|
||||
<h2 class="${styles.modalTitle}">Manage cookie preferences</h2>
|
||||
</div>
|
||||
|
||||
<form class="${styles.modalContent}">
|
||||
<p class="${styles.cookieStatement}">Most Microsoft sites use cookies</p>
|
||||
|
||||
<ol class="${styles.cookieOrderedList}">
|
||||
<li class="${styles.cookieListItem}">
|
||||
<h3 class="${styles.cookieListItemTitle}">1. Essential cookies</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use essential cookies</p>
|
||||
</li>
|
||||
|
||||
<li class="${styles.cookieListItem}">
|
||||
<div class="${styles.cookieListItemGroup}" role="radiogroup" aria-label="Performance cookies setting">
|
||||
<h3 class="${styles.cookieListItemTitle}">2. Performance</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use performance</p>
|
||||
<div class="${styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Accept" class="${styles.cookieItemRadioBtn}" name="performanceCookies" value="accept">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Accept</span>
|
||||
</label>
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Reject" class="${styles.cookieItemRadioBtn}" name="performanceCookies" value="reject">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Reject</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="${styles.cookieListItem}">
|
||||
<div class="${styles.cookieListItemGroup}" role="radiogroup" aria-label="Advertising cookies setting">
|
||||
<h3 class="${styles.cookieListItemTitle}">3. Advertising</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use advertising</p>
|
||||
<div class="${styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Accept" class="${styles.cookieItemRadioBtn}" name="advertisingCookies" value="accept" checked>
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Accept</span>
|
||||
</label>
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Reject" class="${styles.cookieItemRadioBtn}" name="advertisingCookies" value="reject">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Reject</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="${styles.cookieListItem}">
|
||||
<div class="${styles.cookieListItemGroup}" role="radiogroup" aria-label="Targeting cookies setting">
|
||||
<h3 class="${styles.cookieListItemTitle}">4. Targeting</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use targeting</p>
|
||||
<div class="${styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Accept" class="${styles.cookieItemRadioBtn}" name="targetingCookies" value="accept">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Accept</span>
|
||||
</label>
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Reject" class="${styles.cookieItemRadioBtn}" name="targetingCookies" value="reject" checked>
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Reject</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</form>
|
||||
|
||||
<div class="${styles.modalButtonGroup}">
|
||||
<button type="button" aria-label="Save changes" class="${styles.modalButtonSave}" disabled>Save changes</button>
|
||||
<button type="button" aria-label="Reset all" class="${styles.modalButtonReset}" disabled>Reset all</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
function testRemovingBanner(): void {
|
||||
let bannerBody = document.getElementsByClassName(styles.bannerBody);
|
||||
expect(bannerBody.length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.bannerInform).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.infoIcon).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.bannerInformBody).length).toBe(0);
|
||||
|
||||
expect(document.getElementsByClassName(styles.buttonGroup).length).toBe(0);
|
||||
expect(document.getElementsByClassName(styles.bannerButton).length).toBe(0);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Pass string in constructor, and banner will be inserted when showBanner(...) is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
cc.showBanner({ "c1": true, "c2": false,"c3": undefined });
|
||||
|
||||
testShowingBanner(cc.getDirection());
|
||||
});
|
||||
|
||||
test("Pass HTMLElement in constructor, and banner will be inserted when showBanner(...) is called", () => {
|
||||
let insert = document.getElementById(testId);
|
||||
|
||||
if (insert) {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(insert, "en", callBack);
|
||||
cc.showBanner({ "c1": true, "c2": false,"c3": undefined });
|
||||
|
||||
testShowingBanner(cc.getDirection());
|
||||
}
|
||||
});
|
||||
|
||||
test("Pass string in constructor, and preferences dialog will be inserted when showBanner(...) is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": undefined, "c3": false };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "");
|
||||
});
|
||||
|
||||
test("Pass HTMLElement in constructor, and preferences dialog will be inserted when showBanner(...) is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let insert = document.getElementById(testId);
|
||||
|
||||
if (insert) {
|
||||
let cc = new ConsentControl(insert, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": undefined, "c3": false };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "");
|
||||
}
|
||||
});
|
||||
|
||||
test("Call showBanner(...) many times, only keep last one", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
cc.showBanner({ "c1": true, "c2": false,"c3": undefined });
|
||||
cc.showBanner({ "c1": false, "c2": true,"c3": undefined });
|
||||
cc.showBanner({ "c1": true, "c2": false,"c3": false });
|
||||
|
||||
testShowingBanner(cc.getDirection());
|
||||
testShowingPreferences(cc, { "c1": true, "c2": false,"c3": false }, "");
|
||||
});
|
||||
|
||||
test("If switchable id is not in cookieCategoriePreferences, the category in preferences dialog will not be set", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c2": true, "c3": undefined };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "");
|
||||
});
|
||||
|
||||
test("Preferences dialog will appear when 'More info' button is clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
let cookieInfo: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[1];
|
||||
cookieInfo.click();
|
||||
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "block");
|
||||
});
|
||||
|
||||
test("'Reset all' and 'Save changes' will be enabled when any radio buttons are clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
cc.showBanner({ "c1": true, "c2": false,"c3": undefined });
|
||||
|
||||
let cookieItemRadioBtnLength = document.getElementsByClassName(styles.cookieItemRadioBtn).length;
|
||||
for (let i = 0; i < cookieItemRadioBtnLength; i++) {
|
||||
let container = document.getElementById(testId);
|
||||
if (container) {
|
||||
container.innerHTML = "";
|
||||
|
||||
let otherCallBack = function() { return; };
|
||||
let otherCc = new ConsentControl(testId, "en", otherCallBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
let cookiePreferencesBtnArray = [0, 3];
|
||||
|
||||
otherCc.showBanner(cookieCategoriePreferences);
|
||||
testModalSaveButton(i, cookiePreferencesBtnArray);
|
||||
}
|
||||
else {
|
||||
throw new Error("Container not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("'Reset all' will be enabled when any cookieCategoriesPreferences is defined", () => {
|
||||
let callBack = function() { return; };
|
||||
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
let cookieCategoriesPreferences: ICookieCategoriesPreferences = { };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeTruthy();
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c1": true };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c1": false };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c2": true };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c2": false };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c3": true };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c3": false };
|
||||
cc.showBanner(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hideBanner();
|
||||
});
|
||||
|
||||
test("Preferences dialog will be removed from DOM when 'X' button is clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
cc.showBanner({ "c1": true, "c2": false,"c3": undefined });
|
||||
|
||||
let closeModalIcon: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.closeModalIcon)[0];
|
||||
closeModalIcon.click();
|
||||
|
||||
expect(cc.preferencesCtrl).toBeNull();
|
||||
testRemovingPreferences();
|
||||
});
|
||||
|
||||
test("'X' button is clicked, and then click 'More info' button. Preferences dialog should appear", () => {
|
||||
let callBack = function() { return; };
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false,"c3": undefined };
|
||||
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
cc.showBanner(cookieCategoriePreferences);
|
||||
|
||||
let closeModalIcon: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.closeModalIcon)[0];
|
||||
closeModalIcon.click();
|
||||
|
||||
let cookieInfo: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[1];
|
||||
cookieInfo.click();
|
||||
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "block");
|
||||
|
||||
closeModalIcon.click();
|
||||
cookieInfo.click();
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "block");
|
||||
});
|
||||
|
||||
test("Banner will be removed from DOM when hideBanner() is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let insert = document.getElementById(testId);
|
||||
if (insert) {
|
||||
insert.innerHTML = testElementString;
|
||||
}
|
||||
else {
|
||||
throw new Error("Insert point not found error");
|
||||
}
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
testRemovingBanner()
|
||||
});
|
||||
|
||||
test("Preferences dialog will be removed from DOM when hideBanner() is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let insert = document.getElementById(testId);
|
||||
if (insert) {
|
||||
insert.innerHTML = testElementString;
|
||||
}
|
||||
else {
|
||||
throw new Error("Insert point not found error");
|
||||
}
|
||||
|
||||
// We only want to test hideBanner() function, so we create HTML elements and preferencesCtrl.
|
||||
let cookieCategoriePreferences = { "c1": undefined, "c2": true, "c3": false };
|
||||
cc.preferencesCtrl = new PreferencesControl(cc.cookieCategories,
|
||||
cc.textResources,
|
||||
cookieCategoriePreferences,
|
||||
insert,
|
||||
"ltr",
|
||||
() => { cc.preferencesCtrl = null; });
|
||||
|
||||
cc.hideBanner();
|
||||
|
||||
expect(cc.preferencesCtrl).toBeNull();
|
||||
testRemovingPreferences();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test show and hide preferences dialog", () => {
|
||||
let testId: string = "app";
|
||||
let testElementBanner = `
|
||||
<div class="${styles.bannerBody}" dir=ltr role="alert">
|
||||
<div class="${styles.bannerInform}">
|
||||
<span class="${styles.infoIcon}" aria-label="Information message"></span> <!-- used for icon -->
|
||||
<p class="${styles.bannerInformBody}">We use </p>
|
||||
</div>
|
||||
|
||||
<div class="${styles.buttonGroup}">
|
||||
<button type="button" class="${styles.bannerButton}">Accept all</button>
|
||||
<button type="button" class="${styles.bannerButton}">More info</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
let testElementString = `
|
||||
<!-- The Modal -->
|
||||
<div class="${styles.cookieModal}" dir=ltr>
|
||||
<div role="presentation" tabindex="-1"></div>
|
||||
<div role="dialog" aria-modal="true" aria-label="Flow scroll" class="${styles.modalContainer}" tabindex="-1">
|
||||
<button aria-label="Close dialog" class="${styles.closeModalIcon}" tabindex="0">✕</button>
|
||||
<div role="document" class="${styles.modalBody}">
|
||||
<div>
|
||||
<h2 class="${styles.modalTitle}">Manage cookie preferences</h2>
|
||||
</div>
|
||||
|
||||
<form class="${styles.modalContent}">
|
||||
<p class="${styles.cookieStatement}">Most Microsoft sites use cookies</p>
|
||||
|
||||
<ol class="${styles.cookieOrderedList}">
|
||||
<li class="${styles.cookieListItem}">
|
||||
<h3 class="${styles.cookieListItemTitle}">1. Essential cookies</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use essential cookies</p>
|
||||
</li>
|
||||
|
||||
<li class="${styles.cookieListItem}">
|
||||
<div class="${styles.cookieListItemGroup}" role="radiogroup" aria-label="Performance cookies setting">
|
||||
<h3 class="${styles.cookieListItemTitle}">2. Performance</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use performance</p>
|
||||
<div class="${styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Accept" class="${styles.cookieItemRadioBtn}" name="performanceCookies" value="accept">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Accept</span>
|
||||
</label>
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Reject" class="${styles.cookieItemRadioBtn}" name="performanceCookies" value="reject">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Reject</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="${styles.cookieListItem}">
|
||||
<div class="${styles.cookieListItemGroup}" role="radiogroup" aria-label="Advertising cookies setting">
|
||||
<h3 class="${styles.cookieListItemTitle}">3. Advertising</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use advertising</p>
|
||||
<div class="${styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Accept" class="${styles.cookieItemRadioBtn}" name="advertisingCookies" value="accept" checked>
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Accept</span>
|
||||
</label>
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Reject" class="${styles.cookieItemRadioBtn}" name="advertisingCookies" value="reject">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Reject</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="${styles.cookieListItem}">
|
||||
<div class="${styles.cookieListItemGroup}" role="radiogroup" aria-label="Targeting cookies setting">
|
||||
<h3 class="${styles.cookieListItemTitle}">4. Targeting</h3>
|
||||
<p class="${styles.cookieListItemDescription}">We use targeting</p>
|
||||
<div class="${styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Accept" class="${styles.cookieItemRadioBtn}" name="targetingCookies" value="accept">
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Accept</span>
|
||||
</label>
|
||||
<label class="${styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
<input type="radio" aria-label="Reject" class="${styles.cookieItemRadioBtn}" name="targetingCookies" value="reject" checked>
|
||||
<span class="${styles.cookieItemRadioBtnLabel}">Reject</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</form>
|
||||
|
||||
<div class="${styles.modalButtonGroup}">
|
||||
<button type="button" aria-label="Save changes" class="${styles.modalButtonSave}" disabled>Save changes</button>
|
||||
<button type="button" aria-label="Reset all" class="${styles.modalButtonReset}" disabled>Reset all</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
newDiv.innerHTML = testElementBanner;
|
||||
|
||||
document.body.appendChild(newDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Pass string in constructor, and preferences dialog will be inserted when showPreferences(...) is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": undefined, "c3": false };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
testShowingBanner("ltr");
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "block");
|
||||
});
|
||||
|
||||
test("Pass HTMLElement in constructor, and preferences dialog will be inserted when showPreferences(...) is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let insert = document.getElementById(testId);
|
||||
|
||||
if (insert) {
|
||||
let cc = new ConsentControl(insert, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": undefined, "c3": false };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
testShowingBanner("ltr");
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "block");
|
||||
}
|
||||
});
|
||||
|
||||
test("If switchable id is not in cookieCategoriePreferences, the category in preferences dialog will not be set when showPreferences(...) is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c3": undefined };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
testShowingBanner("ltr");
|
||||
testShowingPreferences(cc, cookieCategoriePreferences, "block");
|
||||
});
|
||||
|
||||
test("'Reset all' and 'Save changes' will be enabled when any radio buttons are clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
let cookieItemRadioBtnLength = document.getElementsByClassName(styles.cookieItemRadioBtn).length;
|
||||
for (let i = 0; i < cookieItemRadioBtnLength; i++) {
|
||||
let container = document.getElementById(testId);
|
||||
if (container) {
|
||||
container.innerHTML = "";
|
||||
|
||||
let otherCallBack = function() { return; };
|
||||
let otherCc = new ConsentControl(testId, "en", otherCallBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
let cookiePreferencesBtnArray = [0, 3];
|
||||
|
||||
otherCc.showPreferences(cookieCategoriePreferences);
|
||||
testModalSaveButton(i, cookiePreferencesBtnArray);
|
||||
}
|
||||
else {
|
||||
throw new Error("Container not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("'Reset all' will be enabled when any cookieCategoriesPreferences is defined", () => {
|
||||
let callBack = function() { return; };
|
||||
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
let cookieCategoriesPreferences: ICookieCategoriesPreferences = { };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeTruthy();
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c1": true };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c1": false };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c2": true };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c2": false };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c3": true };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
cc = new ConsentControl(testId, "en", callBack);
|
||||
cookieCategoriesPreferences = { "c3": false };
|
||||
cc.showPreferences(cookieCategoriesPreferences);
|
||||
expect((<HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0]).disabled).toBeFalsy();
|
||||
|
||||
cc.hidePreferences();
|
||||
});
|
||||
|
||||
test("Preferences dialog will be removed from DOM when 'X' button is clicked", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let cookieCategoriePreferences = { "c1": true, "c2": false, "c3": undefined };
|
||||
cc.showPreferences(cookieCategoriePreferences);
|
||||
|
||||
let closeModalIcon: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.closeModalIcon)[0];
|
||||
closeModalIcon.click();
|
||||
|
||||
testShowingBanner("ltr");
|
||||
expect(cc.preferencesCtrl).toBeNull();
|
||||
testRemovingPreferences();
|
||||
});
|
||||
|
||||
test("Preferences dialog will be removed from DOM when hidePreferences() is called", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let insert = document.getElementById(testId);
|
||||
if (insert) {
|
||||
insert.innerHTML = testElementBanner + testElementString;
|
||||
}
|
||||
else {
|
||||
throw new Error("Insert point not found error");
|
||||
}
|
||||
|
||||
// We only want to test hidePreferences() function, so we create HTML elements and preferencesCtrl.
|
||||
let cookieCategoriePreferences = { "c1": undefined, "c2": true, "c3": false };
|
||||
cc.preferencesCtrl = new PreferencesControl(cc.cookieCategories,
|
||||
cc.textResources,
|
||||
cookieCategoriePreferences,
|
||||
insert,
|
||||
"ltr",
|
||||
() => { cc.preferencesCtrl = null; });
|
||||
|
||||
cc.hidePreferences();
|
||||
|
||||
testShowingBanner("ltr");
|
||||
expect(cc.preferencesCtrl).toBeNull();
|
||||
testRemovingPreferences();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test containerElement", () => {
|
||||
let testId: string = "app";
|
||||
let testId2: string = "app2";
|
||||
|
||||
beforeEach(() => {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.setAttribute("id", testId);
|
||||
document.body.appendChild(newDiv);
|
||||
|
||||
let newDiv2 = document.createElement("div");
|
||||
newDiv2.setAttribute("id", testId2);
|
||||
document.body.appendChild(newDiv2);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
let child = document.getElementById(testId);
|
||||
if (child) {
|
||||
let parent = child.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent 1 not found error");
|
||||
}
|
||||
}
|
||||
|
||||
let child2 = document.getElementById(testId2);
|
||||
if (child2) {
|
||||
let parent2 = child2.parentNode;
|
||||
|
||||
if (parent2) {
|
||||
parent2.removeChild(child2);
|
||||
}
|
||||
else {
|
||||
throw new Error("Parent 2 not found error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Use setContainerElement(containerElement: string) to change container", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
cc.setContainerElement(testId2);
|
||||
|
||||
expect(cc.getContainerElement()).toBeTruthy();
|
||||
expect(cc.getContainerElement()?.nodeName).toBe("DIV");
|
||||
expect(cc.getContainerElement()?.getAttribute("id")).toBe(testId2);
|
||||
});
|
||||
|
||||
test("Use setContainerElement(containerElement: HTMLElement) to change container", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
let container = document.getElementById(testId2);
|
||||
if (container) {
|
||||
cc.setContainerElement(container);
|
||||
|
||||
expect(cc.getContainerElement()).toBeTruthy();
|
||||
expect(cc.getContainerElement()?.nodeName).toBe("DIV");
|
||||
expect(cc.getContainerElement()?.getAttribute("id")).toBe(testId2);
|
||||
}
|
||||
else {
|
||||
throw new Error("Container not found error");
|
||||
}
|
||||
});
|
||||
|
||||
test("Use invalid id in setContainerElement(containerElement: string) to change container", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
expect(() => cc.setContainerElement("testId")).toThrow('Container not found error');
|
||||
});
|
||||
|
||||
test("Use empty element in setContainerElement(containerElement) to change container", () => {
|
||||
let callBack = function() { return; };
|
||||
let cc = new ConsentControl(testId, "en", callBack);
|
||||
|
||||
expect(() => cc.setContainerElement("")).toThrow('Container not found error');
|
||||
expect(() => cc.setContainerElement(<HTMLElement> document.getElementById("test"))).toThrow('Container not found error');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,343 @@
|
|||
import * as styles from './styles.scss';
|
||||
import { PreferencesControl } from './preferencesControl';
|
||||
import { HtmlTools } from './htmlTools';
|
||||
|
||||
import { RTL_LANGUAGE } from './language-list.const';
|
||||
import { ICookieCategory } from './interfaces/CookieCategories';
|
||||
import { ITextResources } from './interfaces/TextResources';
|
||||
import { ICookieCategoriesPreferences } from './interfaces/CookieCategoriesPreferences';
|
||||
|
||||
export class ConsentControl {
|
||||
private containerElement: HTMLElement | null = null; // here the banner will be inserted
|
||||
culture: string;
|
||||
|
||||
// callback function, called on preferences changes (via "Accept All", or "Save changes")
|
||||
onPreferencesChanged: (cookieCategoriesPreferences: ICookieCategoriesPreferences) => void;
|
||||
|
||||
cookieCategories: ICookieCategory[];
|
||||
textResources: ITextResources;
|
||||
|
||||
preferencesCtrl: PreferencesControl | null = null;
|
||||
private direction: string = 'ltr';
|
||||
|
||||
// All categories should be replaced with the passed ones in the control
|
||||
defaultCookieCategories: ICookieCategory[] =
|
||||
[
|
||||
{
|
||||
id: "c0",
|
||||
name: "1. Essential cookies",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>.",
|
||||
isUnswitchable: true // optional, prevents toggling the category. True only for categories like Essential cookies.
|
||||
},
|
||||
{
|
||||
id: "c1",
|
||||
name: "2. Performance & analytics",
|
||||
descHtml: "We use this cookie, read more <a href='link'>here</a>."
|
||||
},
|
||||
{
|
||||
id: "c2",
|
||||
name: "3. Advertising/Marketing",
|
||||
descHtml: "Blah"
|
||||
},
|
||||
{
|
||||
id: "c3",
|
||||
name: "4. Targeting/personalization",
|
||||
descHtml: "Blah"
|
||||
}
|
||||
];
|
||||
|
||||
// only the passed text resources should be replaced in the control.
|
||||
// If any string is not passed the control should keep the default value
|
||||
defaultTextResources: ITextResources = {
|
||||
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
|
||||
acceptAllLabel: "Accept all",
|
||||
moreInfoLabel: "More info",
|
||||
preferencesDialogCloseLabel: "Close",
|
||||
preferencesDialogTitle: "Manage cookie preferences",
|
||||
preferencesDialogDescHtml: "Most Microsoft sites...",
|
||||
acceptLabel: "Accept",
|
||||
rejectLabel: "Reject",
|
||||
saveLabel: "Save changes",
|
||||
resetLabel: "Reset all"
|
||||
};
|
||||
|
||||
constructor(containerElementOrId: string | HTMLElement,
|
||||
culture: string,
|
||||
onPreferencesChanged: (cookieCategoriesPreferences: ICookieCategoriesPreferences) => void,
|
||||
cookieCategories?: ICookieCategory[],
|
||||
textResources?: ITextResources) {
|
||||
|
||||
this.setContainerElement(containerElementOrId);
|
||||
|
||||
this.culture = culture;
|
||||
this.onPreferencesChanged = onPreferencesChanged;
|
||||
|
||||
if (cookieCategories) {
|
||||
this.cookieCategories = cookieCategories;
|
||||
}
|
||||
else {
|
||||
this.cookieCategories = this.defaultCookieCategories;
|
||||
}
|
||||
|
||||
this.textResources = this.defaultTextResources;
|
||||
if (textResources) {
|
||||
this.setTextResources(textResources);
|
||||
}
|
||||
|
||||
this.setDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text resources for the banner to display the text in each area
|
||||
*
|
||||
* @param {ITextResources} textResources the text want to be displayed
|
||||
*/
|
||||
public setTextResources(textResources: ITextResources): void {
|
||||
if (textResources.bannerMessageHtml) {
|
||||
this.textResources.bannerMessageHtml = textResources.bannerMessageHtml;
|
||||
}
|
||||
if (textResources.acceptAllLabel) {
|
||||
this.textResources.acceptAllLabel = textResources.acceptAllLabel;
|
||||
}
|
||||
if (textResources.moreInfoLabel) {
|
||||
this.textResources.moreInfoLabel = textResources.moreInfoLabel;
|
||||
}
|
||||
if (textResources.preferencesDialogCloseLabel) {
|
||||
this.textResources.preferencesDialogCloseLabel = textResources.preferencesDialogCloseLabel;
|
||||
}
|
||||
if (textResources.preferencesDialogTitle) {
|
||||
this.textResources.preferencesDialogTitle = textResources.preferencesDialogTitle;
|
||||
}
|
||||
if (textResources.preferencesDialogDescHtml) {
|
||||
this.textResources.preferencesDialogDescHtml = textResources.preferencesDialogDescHtml;
|
||||
}
|
||||
if (textResources.acceptLabel) {
|
||||
this.textResources.acceptLabel = textResources.acceptLabel;
|
||||
}
|
||||
if (textResources.rejectLabel) {
|
||||
this.textResources.rejectLabel = textResources.rejectLabel;
|
||||
}
|
||||
if (textResources.saveLabel) {
|
||||
this.textResources.saveLabel = textResources.saveLabel;
|
||||
}
|
||||
if (textResources.resetLabel) {
|
||||
this.textResources.resetLabel = textResources.resetLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all necessary HTML code and shows the banner.
|
||||
* Until this method is called there should be no HTML elements of the Consent Control anywhere in the DOM
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
public showBanner(cookieCategoriesPreferences: ICookieCategoriesPreferences): void {
|
||||
// Add <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
// for responsive web design
|
||||
if (!document.querySelector('meta[name="viewport"]')) {
|
||||
let meta = document.createElement('meta');
|
||||
meta.name = "viewport";
|
||||
meta.content = "width=device-width, initial-scale=1.0";
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
}
|
||||
|
||||
// Remove existing banner and preference dialog
|
||||
this.hideBanner();
|
||||
|
||||
let infoIcon = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" x='0px' y='0px' viewBox='0 0 44 44' width='24px' height='24px' fill='none' stroke='currentColor'>
|
||||
<circle cx='22' cy='22' r='20' stroke-width='2'></circle>
|
||||
<line x1='22' x2='22' y1='18' y2='33' stroke-width='3'></line>
|
||||
<line x1='22' x2='22' y1='12' y2='15' stroke-width='3'></line>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
const bannerInnerHtml = `
|
||||
<div class="${ styles.bannerInform }">
|
||||
<span class="${ styles.infoIcon }">${ infoIcon }</span> <!-- used for icon -->
|
||||
<p class="${ styles.bannerInformBody }">
|
||||
${ this.textResources.bannerMessageHtml }
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="${ styles.buttonGroup }">
|
||||
<button type="button" class="${ styles.bannerButton }">${ HtmlTools.escapeHtml(this.textResources.acceptAllLabel) }</button>
|
||||
<button type="button" class="${ styles.bannerButton }">${ HtmlTools.escapeHtml(this.textResources.moreInfoLabel) }</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const banner = document.createElement('div');
|
||||
banner.setAttribute('id','wcpConsentBannerCtrl');
|
||||
banner.setAttribute('class', styles.bannerBody);
|
||||
banner.setAttribute('dir', this.direction);
|
||||
banner.setAttribute('role', 'alert');
|
||||
banner.innerHTML = bannerInnerHtml;
|
||||
|
||||
this.containerElement?.appendChild(banner);
|
||||
|
||||
if (!this.preferencesCtrl) {
|
||||
this.initPreferencesCtrl(cookieCategoriesPreferences);
|
||||
|
||||
// Add event handler to show preferences dialog (from hidden state) when "More info" button is clicked
|
||||
let cookieInfo = document.getElementsByClassName(styles.bannerButton)[1];
|
||||
cookieInfo?.addEventListener('click', () => this.showPreferences(cookieCategoriesPreferences));
|
||||
}
|
||||
|
||||
let acceptAllBtn = <HTMLElement> document.getElementsByClassName(styles.bannerButton)[0];
|
||||
acceptAllBtn?.addEventListener('click', () => this.onAcceptAllClicked(cookieCategoriesPreferences));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the banner and the Preferences Dialog.
|
||||
* Removes all HTML elements of the Consent Control from the DOM
|
||||
*/
|
||||
public hideBanner(): void {
|
||||
if (document.getElementsByClassName(styles.bannerBody)) {
|
||||
let bannerArray = [].slice.call(document.getElementsByClassName(styles.bannerBody));
|
||||
for (let singleBanner of bannerArray) {
|
||||
this.containerElement?.removeChild(singleBanner);
|
||||
}
|
||||
this.hidePreferences();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows Preferences Dialog. Leaves banner state unchanged
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
public showPreferences(cookieCategoriesPreferences: ICookieCategoriesPreferences): void {
|
||||
if (!this.preferencesCtrl) {
|
||||
this.initPreferencesCtrl(cookieCategoriesPreferences);
|
||||
}
|
||||
|
||||
this.preferencesCtrl?.showPreferencesDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides Preferences Dialog.
|
||||
* Removes all HTML elements of the Preferences Dialog from the DOM. Leaves banner state unchanged
|
||||
*/
|
||||
public hidePreferences(): void {
|
||||
if (!this.preferencesCtrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.preferencesCtrl.hidePreferencesDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* The method is used to initialize the preferences dialog.
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
private initPreferencesCtrl(cookieCategoriesPreferences: ICookieCategoriesPreferences): void {
|
||||
|
||||
this.preferencesCtrl = new PreferencesControl(this.cookieCategories,
|
||||
this.textResources,
|
||||
cookieCategoriesPreferences,
|
||||
<HTMLElement> this.containerElement,
|
||||
this.direction,
|
||||
() => this.onPreferencesClosed());
|
||||
|
||||
this.preferencesCtrl.createPreferencesDialog();
|
||||
|
||||
// Add event handler to "Save changes" button event
|
||||
this.preferencesCtrl.addSaveButtonEvent(() => this.onPreferencesChanged(cookieCategoriesPreferences));
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that will be called when "Accept all" button is clicked
|
||||
*
|
||||
* @param {ICookieCategoriesPreferences} cookieCategoriesPreferences object that indicates cookie categories preferences
|
||||
*/
|
||||
private onAcceptAllClicked(cookieCategoriesPreferences: ICookieCategoriesPreferences): void {
|
||||
for (let cookieCategory of this.cookieCategories) {
|
||||
if (!cookieCategory.isUnswitchable) {
|
||||
cookieCategoriesPreferences[cookieCategory.id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.onPreferencesChanged(cookieCategoriesPreferences);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that is used to set preferencesCtrl property to null
|
||||
*/
|
||||
private onPreferencesClosed(): void {
|
||||
this.preferencesCtrl = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the container that will be used for the banner
|
||||
*
|
||||
* @param {string | HTMLElement} containerElementOrId here the banner will be inserted
|
||||
*/
|
||||
public setContainerElement(containerElementOrId: string | HTMLElement): void {
|
||||
if (containerElementOrId instanceof Element) {
|
||||
this.containerElement = containerElementOrId;
|
||||
}
|
||||
else if (containerElementOrId && containerElementOrId.length > 0) { // containerElementOrId: string
|
||||
this.containerElement = document.querySelector('#' + containerElementOrId);
|
||||
}
|
||||
else {
|
||||
this.containerElement = null;
|
||||
}
|
||||
|
||||
if (!this.containerElement) {
|
||||
throw new Error("Container not found error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the container that is used for the banner
|
||||
*/
|
||||
public getContainerElement(): HTMLElement | null {
|
||||
return this.containerElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the direction by passing the parameter or by checking the culture property
|
||||
*
|
||||
* @param {string} dir direction for the web, ltr or rtl
|
||||
*/
|
||||
public setDirection(dir?: string): void {
|
||||
if (dir) {
|
||||
this.direction = dir;
|
||||
}
|
||||
else {
|
||||
let formatCulture: string = this.culture.toLowerCase();
|
||||
let cultureArray: string[] = formatCulture.split('-');
|
||||
let lang: string = cultureArray[0];
|
||||
|
||||
// Check <html dir="rtl"> or <html dir="ltr">
|
||||
if (document.dir) {
|
||||
this.direction = document.dir;
|
||||
}
|
||||
// Check <body dir="rtl"> or <body dir="ltr">
|
||||
else if (document.body.dir) {
|
||||
this.direction = document.body.dir;
|
||||
}
|
||||
else {
|
||||
if (RTL_LANGUAGE.indexOf(lang) !== -1) {
|
||||
this.direction = 'rtl';
|
||||
}
|
||||
// ks-Arab-IN is right to left (in language-list.const.ts)
|
||||
// ks-Deva-IN is left to right
|
||||
else if (RTL_LANGUAGE.indexOf(cultureArray[0] + '-' + cultureArray[1]) !== -1) {
|
||||
this.direction = 'rtl';
|
||||
}
|
||||
else {
|
||||
this.direction = 'ltr';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the direction
|
||||
*/
|
||||
public getDirection(): string {
|
||||
return this.direction;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export interface ICookieCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
descHtml: string;
|
||||
isUnswitchable?: boolean; // optional, prevents toggling the category. True only for categories like Essential cookies.
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface ICookieCategoriesPreferences {
|
||||
[key: string]: boolean | undefined;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
export interface ITextResources {
|
||||
bannerMessageHtml?: string;
|
||||
acceptAllLabel?: string;
|
||||
moreInfoLabel?: string;
|
||||
preferencesDialogCloseLabel?: string;
|
||||
preferencesDialogTitle?: string;
|
||||
preferencesDialogDescHtml?: string;
|
||||
acceptLabel?: string;
|
||||
rejectLabel?: string;
|
||||
saveLabel?: string;
|
||||
resetLabel?: string;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// culture can be just language "en" or language-country "en-us".
|
||||
// Based on language RTL should be applied (https://www.w3.org/International/questions/qa-scripts.en)
|
||||
// Locale IDs are from
|
||||
// https://help.bing.microsoft.com/#apex/18/en-US/10004/-1
|
||||
// https://docs.microsoft.com/en-us/openspecs/office_standards/ms-oe376/6c085406-a698-4e12-9d4d-c3b0ee3dbc4a
|
||||
export const RTL_LANGUAGE: string[] = [
|
||||
'ar',
|
||||
'he',
|
||||
'ps',
|
||||
'ur',
|
||||
'fa',
|
||||
'pa',
|
||||
'sd',
|
||||
'tk',
|
||||
'ug',
|
||||
'yi',
|
||||
'syr',
|
||||
'ks-arab' // Kashmiri (Arabic) is rtl
|
||||
];
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
import * as styles from "./styles.scss";
|
||||
import { HtmlTools } from './htmlTools';
|
||||
|
||||
import { ICookieCategory } from './interfaces/CookieCategories';
|
||||
import { ITextResources } from './interfaces/TextResources';
|
||||
import { ICookieCategoriesPreferences } from './interfaces/CookieCategoriesPreferences';
|
||||
|
||||
export class PreferencesControl {
|
||||
cookieCategories: ICookieCategory[];
|
||||
textResources: ITextResources;
|
||||
cookieCategoriesPreferences: ICookieCategoriesPreferences;
|
||||
|
||||
private containerElement: HTMLElement;
|
||||
private direction: string = 'ltr';
|
||||
private onPreferencesClosed: () => void;
|
||||
|
||||
constructor(cookieCategories: ICookieCategory[],
|
||||
textResources: ITextResources,
|
||||
cookieCategoriesPreferences: ICookieCategoriesPreferences,
|
||||
containerElement: HTMLElement,
|
||||
direction: string,
|
||||
onPreferencesClosed: () => void) {
|
||||
|
||||
this.cookieCategories = cookieCategories;
|
||||
this.textResources = textResources;
|
||||
this.cookieCategoriesPreferences = cookieCategoriesPreferences;
|
||||
this.containerElement = containerElement;
|
||||
this.direction = direction;
|
||||
this.onPreferencesClosed = onPreferencesClosed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hidden Preferences Dialog and insert in the bottom of the container.
|
||||
*
|
||||
* @param {boolean} banner true for banner, false for preferences dialog.
|
||||
*/
|
||||
public createPreferencesDialog(): void {
|
||||
let cookieModalInnerHtml = `
|
||||
<div role="presentation" tabindex="-1"></div>
|
||||
<div role="dialog" aria-modal="true" aria-label="${ HtmlTools.escapeHtml(this.textResources.preferencesDialogTitle) }" class="${ styles.modalContainer }" tabindex="-1">
|
||||
<button aria-label="${ HtmlTools.escapeHtml(this.textResources.preferencesDialogCloseLabel) }" class="${ styles.closeModalIcon }" tabindex="0">✕</button>
|
||||
<div role="document" class="${ styles.modalBody }">
|
||||
<div>
|
||||
<h2 class="${styles.modalTitle}">${ HtmlTools.escapeHtml(this.textResources.preferencesDialogTitle) }</h2>
|
||||
</div>
|
||||
|
||||
<form class="${ styles.modalContent }">
|
||||
<p class="${ styles.cookieStatement }">
|
||||
${ this.textResources.preferencesDialogDescHtml }
|
||||
</p>
|
||||
|
||||
<ol class="${ styles.cookieOrderedList }">
|
||||
</ol>
|
||||
</form>
|
||||
|
||||
<div class="${ styles.modalButtonGroup }">
|
||||
<button type="button" aria-label="${ HtmlTools.escapeHtml(this.textResources.saveLabel) }" class="${ styles.modalButtonSave }" disabled>${ HtmlTools.escapeHtml(this.textResources.saveLabel) }</button>
|
||||
<button type="button" aria-label="${ HtmlTools.escapeHtml(this.textResources.resetLabel) }" class="${ styles.modalButtonReset }" disabled>${ HtmlTools.escapeHtml(this.textResources.resetLabel) }</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const cookieModal = document.createElement('div');
|
||||
cookieModal.setAttribute('id','wcpCookiePreferenceCtrl');
|
||||
cookieModal.setAttribute('class', styles.cookieModal);
|
||||
cookieModal.setAttribute('dir', this.direction);
|
||||
cookieModal.innerHTML = cookieModalInnerHtml;
|
||||
|
||||
this.containerElement.appendChild(cookieModal);
|
||||
|
||||
let enabledResetAll = false;
|
||||
|
||||
// Insert cookie category
|
||||
for (let cookieCategory of this.cookieCategories) {
|
||||
if (cookieCategory.isUnswitchable) {
|
||||
let item = `
|
||||
<li class="${ styles.cookieListItem }">
|
||||
<h3 class="${ styles.cookieListItemTitle }">${ HtmlTools.escapeHtml(cookieCategory.name) }</h3>
|
||||
<p class="${ styles.cookieListItemDescription }">${ cookieCategory.descHtml }</p>
|
||||
</li>
|
||||
`;
|
||||
|
||||
let cookieOrderedList = document.getElementsByClassName(styles.cookieOrderedList)[0];
|
||||
cookieOrderedList.innerHTML += item;
|
||||
}
|
||||
else {
|
||||
if (this.cookieCategoriesPreferences[cookieCategory.id] !== undefined) {
|
||||
enabledResetAll = true;
|
||||
}
|
||||
|
||||
let nameAttribute: string = cookieCategory.id;
|
||||
let acceptValue = this.cookieCategoriesPreferences[cookieCategory.id] === true ? "checked" : "";
|
||||
let rejectValue = this.cookieCategoriesPreferences[cookieCategory.id] === false ? "checked" : "";
|
||||
|
||||
let acceptRadio = `<input type="radio" aria-label="${ HtmlTools.escapeHtml(this.textResources.acceptLabel) }" class="${styles.cookieItemRadioBtn}" name="${nameAttribute}" value="accept" ${acceptValue}>`;
|
||||
let rejectRadio = `<input type="radio" aria-label="${ HtmlTools.escapeHtml(this.textResources.rejectLabel) }" class="${styles.cookieItemRadioBtn}" name="${nameAttribute}" value="reject" ${rejectValue}>`;
|
||||
|
||||
let item = `
|
||||
<li class="${ styles.cookieListItem }">
|
||||
<div class="${ styles.cookieListItemGroup}" role="radiogroup" aria-label="${ HtmlTools.escapeHtml(cookieCategory.name) }">
|
||||
<h3 class="${ styles.cookieListItemTitle }">${ HtmlTools.escapeHtml(cookieCategory.name) }</h3>
|
||||
<p class="${ styles.cookieListItemDescription}">${cookieCategory.descHtml}</p>
|
||||
<div class="${ styles.cookieItemRadioBtnGroup}">
|
||||
<label class="${ styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
${ acceptRadio}
|
||||
<span class="${ styles.cookieItemRadioBtnLabel}">${ HtmlTools.escapeHtml(this.textResources.acceptLabel) }</span>
|
||||
</label>
|
||||
<label class="${ styles.cookieItemRadioBtnCtrl}" role="radio">
|
||||
${ rejectRadio}
|
||||
<span class="${ styles.cookieItemRadioBtnLabel}">${ HtmlTools.escapeHtml(this.textResources.rejectLabel) }</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
`;
|
||||
|
||||
let cookieOrderedList = document.getElementsByClassName(styles.cookieOrderedList)[0];
|
||||
cookieOrderedList.innerHTML += item;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledResetAll) {
|
||||
let modalButtonReset: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0];
|
||||
if (modalButtonReset) {
|
||||
modalButtonReset.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add those event handler
|
||||
this.addPreferencesButtonsEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show preferences dialog (from hidden state)
|
||||
*/
|
||||
public showPreferencesDialog(): void {
|
||||
let modal: HTMLElement = <HTMLElement> document.getElementsByClassName(styles.cookieModal)[0];
|
||||
if (modal) {
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides Preferences Dialog. Removes all HTML elements of the Preferences Dialog from the DOM.
|
||||
*/
|
||||
public hidePreferencesDialog(): void {
|
||||
let cookieModal = document.getElementsByClassName(styles.cookieModal)[0];
|
||||
this.containerElement.removeChild(cookieModal);
|
||||
this.onPreferencesClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add event handlers for handling button events
|
||||
* 1. Click "X" button, preference dialog will be removed from the DOM
|
||||
* 2. Click any "accept/reject" button, "Save changes" and "Reset all" button will be enabled
|
||||
* 3. Click any "accept/reject" button, cookieCategoriesPreferences will be set
|
||||
* 4. Click "Reset all" button, cookieCategoriesPreferences will be reset
|
||||
*/
|
||||
private addPreferencesButtonsEvent(): void {
|
||||
let closeModalIcon = document.getElementsByClassName(styles.closeModalIcon)[0];
|
||||
|
||||
let cookieItemRadioBtn: Element[] = [].slice.call(document.getElementsByClassName(styles.cookieItemRadioBtn));
|
||||
let modalButtonSave: HTMLInputElement = <HTMLInputElement>document.getElementsByClassName(styles.modalButtonSave)[0];
|
||||
let modalButtonReset: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.modalButtonReset)[0];
|
||||
|
||||
closeModalIcon?.addEventListener('click', () => this.hidePreferencesDialog());
|
||||
|
||||
if (cookieItemRadioBtn && cookieItemRadioBtn.length) {
|
||||
for (let radio of cookieItemRadioBtn) {
|
||||
radio.addEventListener('click', () => {
|
||||
let categId = radio.getAttribute('name');
|
||||
if (categId) {
|
||||
let oldCategValue = this.cookieCategoriesPreferences[categId];
|
||||
|
||||
// Change cookieCategoriesPreferences
|
||||
let categValue = radio.getAttribute('value');
|
||||
if (categValue === 'accept') {
|
||||
this.cookieCategoriesPreferences[categId] = true;
|
||||
}
|
||||
else { // categValue === 'reject'
|
||||
this.cookieCategoriesPreferences[categId] = false;
|
||||
}
|
||||
|
||||
// Enable "Save changes" and "Reset all" buttons
|
||||
if (oldCategValue !== this.cookieCategoriesPreferences[categId]) {
|
||||
if (modalButtonSave) {
|
||||
modalButtonSave.disabled = false;
|
||||
}
|
||||
}
|
||||
if (modalButtonReset) {
|
||||
modalButtonReset.disabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
modalButtonReset?.addEventListener('click', () => {
|
||||
if (modalButtonSave) {
|
||||
modalButtonSave.disabled = false;
|
||||
}
|
||||
|
||||
for (let cookieCategory of this.cookieCategories) {
|
||||
if (!cookieCategory.isUnswitchable) {
|
||||
this.cookieCategoriesPreferences[cookieCategory.id] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset UI
|
||||
this.setRadioBtnState();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add event handlers for handling "Save changes" button event.
|
||||
* When "Save changes" button is clicked, "fn" will be executed.
|
||||
*
|
||||
* @param fn function that needs to be executed
|
||||
*/
|
||||
public addSaveButtonEvent(fn: () => void): void {
|
||||
let modalButtonSave: HTMLInputElement = <HTMLInputElement>document.getElementsByClassName(styles.modalButtonSave)[0];
|
||||
modalButtonSave?.addEventListener('click', () => fn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set radio buttons checked/unchecked in Preferences Dialog
|
||||
*/
|
||||
public setRadioBtnState(): void {
|
||||
let i = 0;
|
||||
for (let cookieCategory of this.cookieCategories) {
|
||||
if (cookieCategory.isUnswitchable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let categId = cookieCategory.id;
|
||||
if (this.cookieCategoriesPreferences[categId] === true) {
|
||||
let acceptRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
acceptRadio.checked = true;
|
||||
i++;
|
||||
|
||||
let rejectRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
rejectRadio.checked = false;
|
||||
i++;
|
||||
}
|
||||
else if (this.cookieCategoriesPreferences[categId] === false) {
|
||||
let acceptRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
acceptRadio.checked = false;
|
||||
i++;
|
||||
|
||||
let rejectRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
rejectRadio.checked = true;
|
||||
i++;
|
||||
}
|
||||
else { // cookieCategoriesPreferences[categId] === undefined
|
||||
let acceptRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
acceptRadio.checked = false;
|
||||
i++;
|
||||
|
||||
let rejectRadio: HTMLInputElement = <HTMLInputElement> document.getElementsByClassName(styles.cookieItemRadioBtn)[i];
|
||||
rejectRadio.checked = false;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
$bannerBtnWidth: 150px;
|
||||
$bannerBtnHeight: 36px;
|
||||
|
||||
@mixin bannerFont($weight, $size, $style: normal) {
|
||||
font : {
|
||||
family: Segoe UI, SegoeUI, Arial, sans-serif;
|
||||
style: $style;
|
||||
weight: $weight;
|
||||
size: $size;
|
||||
}
|
||||
}
|
||||
|
||||
// For right-to-left direction
|
||||
@mixin rtlDesign($margin, $padding, $float: none) {
|
||||
div[dir="rtl"] & {
|
||||
margin: $margin;
|
||||
padding: $padding;
|
||||
float: $float;
|
||||
}
|
||||
}
|
||||
|
||||
.bannerBody {
|
||||
position: relative;
|
||||
z-index: 9999; /* on top of the page */
|
||||
width: 100%;
|
||||
background-color: #F2F2F2;
|
||||
text-align: left;
|
||||
|
||||
@at-root div[dir="rtl"]#{ & } {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.bannerInform {
|
||||
display: inline-table;
|
||||
margin : {
|
||||
left: 5%;
|
||||
right: 5%;
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
width: 45%; /* If "calc()" is not supported */
|
||||
|
||||
width: calc(85% - (#{ $bannerBtnWidth } + 3 * 4px) * 2);
|
||||
}
|
||||
|
||||
.infoIcon {
|
||||
display: table-cell;
|
||||
padding: 12px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
@include bannerFont(normal, 24px);
|
||||
|
||||
/* identical to box height */
|
||||
line-height: 24px;
|
||||
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.bannerInformBody {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
|
||||
@include bannerFont(normal, 13px);
|
||||
line-height: 16px;
|
||||
color: #000000;
|
||||
|
||||
/* Add styles to hyperlinks in case websites close the default styles for hyperlinks */
|
||||
& a {
|
||||
color: #0067B8;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonGroup {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
.bannerButton {
|
||||
margin: 4px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
|
||||
width: $bannerBtnWidth;
|
||||
height: $bannerBtnHeight;
|
||||
background-color: #EBEBEB;
|
||||
|
||||
cursor: pointer;
|
||||
@include bannerFont(normal, 15px);
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
|
||||
color: #000000;
|
||||
|
||||
&:hover {
|
||||
color: #000000;
|
||||
background-color: #DBDBDB;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: #DBDBDB;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
|
||||
|
||||
border: 2px solid #000000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.cookieModal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 9999; /* on top of the page */
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
overflow: auto;
|
||||
text-align: left;
|
||||
|
||||
@at-root div[dir="rtl"]#{ & } {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.modalContainer {
|
||||
position: relative;
|
||||
top: 8%;
|
||||
margin : {
|
||||
bottom: 40px;
|
||||
left: auto;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
background-color: #ffffff;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #0067B8;
|
||||
width: 640px;
|
||||
}
|
||||
|
||||
.closeModalIcon {
|
||||
float: right;
|
||||
margin: 2px;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
|
||||
cursor: pointer;
|
||||
@include bannerFont(normal, 13px);
|
||||
line-height: 13px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: #666666;
|
||||
background-color: #ffffff;
|
||||
|
||||
@include rtlDesign(2px, 12px, left);
|
||||
}
|
||||
|
||||
.modalBody {
|
||||
margin : {
|
||||
top: 36px;
|
||||
left: 36px;
|
||||
right: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.modalTitle {
|
||||
margin : {
|
||||
bottom: 12px;
|
||||
}
|
||||
|
||||
@include bannerFont(600, 20px);
|
||||
line-height: 24px;
|
||||
text-transform: none;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.modalContent {
|
||||
height: 446px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cookieStatement {
|
||||
margin : {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
@include bannerFont(normal, 15px);
|
||||
line-height: 20px;
|
||||
color: #000000;
|
||||
|
||||
/* Add styles to hyperlinks in case websites close the default styles for hyperlinks */
|
||||
& a {
|
||||
color: #0067B8;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
ol.cookieOrderedList {
|
||||
margin : {
|
||||
top: 36px;
|
||||
bottom: 0;
|
||||
}
|
||||
padding: 0;
|
||||
|
||||
/* Close the default styles which adds decimal numbers in front of list items */
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li.cookieListItem {
|
||||
margin : {
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
@include bannerFont(600, 18px);
|
||||
line-height: 24px;
|
||||
color: #000000;
|
||||
|
||||
/* Close the default styles which adds decimal numbers in front of list items */
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.cookieListItemGroup {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cookieListItemTitle {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-bottom: none;
|
||||
|
||||
@include bannerFont(600, 18px);
|
||||
line-height: 24px;
|
||||
text-transform: none;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.cookieListItemDescription {
|
||||
display: inline-block;
|
||||
margin : {
|
||||
top: 0;
|
||||
bottom: 16px;
|
||||
}
|
||||
|
||||
@include bannerFont(normal, 15px);
|
||||
line-height: 20px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.cookieItemRadioBtnGroup {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cookieItemRadioBtnCtrl {
|
||||
display: inline-block;
|
||||
margin : {
|
||||
bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin defineRaioInput {
|
||||
border-radius: 50%;
|
||||
outline: none;
|
||||
|
||||
&:checked::after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
border-radius: 50%;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
content: "";
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid #0067B8;
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
border-radius: 50%;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
content: "";
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: 1px solid #0067B8;
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
border-radius: 50%;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
content: "";
|
||||
background-color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
border-radius: 50%;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
content: "";
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type="radio"].cookieItemRadioBtn {
|
||||
display: inline-block;
|
||||
position: relative; /* Adjust the position */
|
||||
margin : {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
cursor: pointer;
|
||||
border: 1px solid #000000;
|
||||
box-sizing: border-box;
|
||||
|
||||
appearance: none;
|
||||
|
||||
/* Define our own radio input in case websites close the default styles for input type radio */
|
||||
@include defineRaioInput;
|
||||
}
|
||||
|
||||
.cookieItemRadioBtnLabel {
|
||||
display: block;
|
||||
float: right;
|
||||
position: relative; /* Adjust the position */
|
||||
margin : {
|
||||
left: 8px;
|
||||
right: 34px;
|
||||
}
|
||||
width: 80%; /* If "calc()" is not supported */
|
||||
|
||||
width: calc(100% - 62px);
|
||||
|
||||
@include bannerFont(normal, 15px);
|
||||
line-height: 20px;
|
||||
/* identical to box height, or 133% */
|
||||
|
||||
text-transform: none;
|
||||
color: #000000;
|
||||
|
||||
@include rtlDesign(0 8px 0 34px, 0, left);
|
||||
}
|
||||
|
||||
.modalButtonGroup {
|
||||
margin : {
|
||||
top: 20px;
|
||||
bottom: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.modalButtonReset {
|
||||
padding: 0;
|
||||
border: none;
|
||||
|
||||
width: 278px;
|
||||
height: 36px;
|
||||
|
||||
cursor: pointer;
|
||||
@include bannerFont(normal, 15px);
|
||||
|
||||
line-height: 20px;
|
||||
/* identical to box height, or 133% */
|
||||
text-align: center;
|
||||
|
||||
color: #000000;
|
||||
background-color: #EBEBEB;
|
||||
|
||||
&:hover {
|
||||
color: #000000;
|
||||
background-color: #DBDBDB;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: #DBDBDB;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
|
||||
|
||||
border: 2px solid #000000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.modalButtonSave {
|
||||
float: right;
|
||||
margin : {
|
||||
left: 10px;
|
||||
}
|
||||
padding: 0;
|
||||
border: none;
|
||||
|
||||
width: 278px;
|
||||
height: 36px;
|
||||
|
||||
cursor: pointer;
|
||||
@include bannerFont(normal, 15px);
|
||||
|
||||
line-height: 20px;
|
||||
/* identical to box height, or 133% */
|
||||
text-align: center;
|
||||
|
||||
color: #FFFFFF;
|
||||
background-color: #0067B8;
|
||||
|
||||
&:hover {
|
||||
color: #FFFFFF;
|
||||
background-color: #0067B8;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: #0067B8;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
|
||||
|
||||
border: 2px solid #000000;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
background-color: rgba(0, 120, 215, 0.2);
|
||||
}
|
||||
|
||||
@include rtlDesign(0 10px 0 0, 0, left);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
/* For mobile phones: */
|
||||
|
||||
.buttonGroup, .bannerInform {
|
||||
margin : {
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
left: 3.75%;
|
||||
right: 3.75%;
|
||||
}
|
||||
|
||||
width: 92.5%;
|
||||
}
|
||||
|
||||
.bannerButton {
|
||||
margin : {
|
||||
bottom: 8px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cookieModal {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modalContainer {
|
||||
top: 1.8%;
|
||||
|
||||
width: 93.33%;
|
||||
height: 96.4%;
|
||||
}
|
||||
|
||||
.modalBody {
|
||||
margin : {
|
||||
top: 24px;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modalContent {
|
||||
height: 62%; /* If "calc()" is not supported */
|
||||
|
||||
height: calc(100% - 225px);
|
||||
}
|
||||
|
||||
.modalButtonReset {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modalButtonSave {
|
||||
margin : {
|
||||
bottom: 12px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
|
||||
@include rtlDesign(0 0 12px 0, 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "es5",
|
||||
"allowJs": true,
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"extends": ["tslint-microsoft-contrib"],
|
||||
"rules": {
|
||||
// coding style
|
||||
"align": [true, "elements", "members", "statements"],
|
||||
"ban-types": [true, ["Object", "Strong typing preferred"], ["AnyAction"]],
|
||||
"function-name": [true, {
|
||||
"static-method-regex": "^[a-z][\\w\\d]+$"
|
||||
}],
|
||||
"quotemark": [true, "double"],
|
||||
"linebreak-style": false,
|
||||
"max-func-body-length": false,
|
||||
"max-line-length": false,
|
||||
"member-ordering": [true, {"order": [
|
||||
"public-static-field",
|
||||
"public-instance-field",
|
||||
"protected-static-field",
|
||||
"protected-instance-field",
|
||||
"private-static-field",
|
||||
"private-instance-field",
|
||||
"public-constructor",
|
||||
"protected-constructor",
|
||||
"private-constructor",
|
||||
"public-static-method",
|
||||
"public-instance-method",
|
||||
"protected-static-method",
|
||||
"private-static-method",
|
||||
"protected-instance-method",
|
||||
"private-instance-method"
|
||||
] }],
|
||||
"newline-before-return": false,
|
||||
"newline-per-chained-call": false,
|
||||
"no-consecutive-blank-lines": [true, 2],
|
||||
"typedef": [true, "parameter", "property-declaration", "member-variable-declaration", "array-destructuring"],
|
||||
"variable-name": [true, "allow-pascal-case", "ban-keywords"],
|
||||
|
||||
// modules
|
||||
"export-name": false,
|
||||
"import-name": false,
|
||||
"no-submodule-imports": false,
|
||||
"no-relative-imports": false,
|
||||
"no-default-export": false,
|
||||
"no-import-side-effect": [true, {"ignore-module": "(\\.png|\\.jpg|\\.svg|\\.css|\\.scss)$"}],
|
||||
"no-implicit-dependencies": [true, "dev"],
|
||||
"ordered-imports": false,
|
||||
|
||||
// documentation
|
||||
"completed-docs": false,
|
||||
"missing-jsdoc": false,
|
||||
|
||||
// best practices
|
||||
"no-floating-promises": true,
|
||||
"no-increment-decrement": false,
|
||||
"no-null-keyword": false,
|
||||
"no-parameter-reassignment": false,
|
||||
"no-unsafe-any": false,
|
||||
"no-unused-expression": [true, "allow-fast-null-checks", "allow-new"],
|
||||
"no-void-expression": [true, "ignore-arrow-function-shorthand"],
|
||||
"jsx-no-lambda": false,
|
||||
"jsx-no-multiline-js": false,
|
||||
"strict-boolean-expressions": false,
|
||||
"underscore-consistent-invocation": false,
|
||||
"use-simple-attributes": false,
|
||||
"no-console": false,
|
||||
|
||||
// tests
|
||||
"mocha-no-side-effect-code": false
|
||||
},
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"node_modules/**/*.ts"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
|
||||
const config = {
|
||||
entry: "./src/index.ts",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "consent-banner.js",
|
||||
libraryTarget: 'umd',
|
||||
library: 'ConsentControl'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
modules: true
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader", options: {
|
||||
ident: "postcss",
|
||||
plugins: () => [
|
||||
postcssPresetEnv({
|
||||
autoprefixer: {
|
||||
flexbox: "no-2009",
|
||||
},
|
||||
stage: 2,
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
modules: {
|
||||
exportGlobals: true,
|
||||
localIdentName: "[path][name]__[local]--[hash:base64:5]" // use '[hash:base64]' for production
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader", options: {
|
||||
ident: "postcss",
|
||||
plugins: () => [
|
||||
require("postcss-preset-env")({
|
||||
autoprefixer: {
|
||||
flexbox: "no-2009",
|
||||
},
|
||||
stage: 2
|
||||
})
|
||||
]
|
||||
}
|
||||
},
|
||||
"sass-loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.ts(x)?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
"awesome-typescript-loader"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [
|
||||
".ts",
|
||||
".js"
|
||||
]
|
||||
},
|
||||
devServer: {
|
||||
contentBase: "./dist",
|
||||
watchContentBase: true
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
|
@ -0,0 +1,92 @@
|
|||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
|
||||
const config = {
|
||||
entry: "./src/index.ts",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "consent-banner.js",
|
||||
libraryTarget: 'umd',
|
||||
library: 'ConsentControl'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
modules: true
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader", options: {
|
||||
ident: "postcss",
|
||||
plugins: () => [
|
||||
postcssPresetEnv({
|
||||
autoprefixer: {
|
||||
flexbox: "no-2009",
|
||||
},
|
||||
stage: 2,
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
modules: {
|
||||
exportGlobals: true,
|
||||
localIdentName: "[hash:base64]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader", options: {
|
||||
ident: "postcss",
|
||||
plugins: () => [
|
||||
require("postcss-preset-env")({
|
||||
autoprefixer: {
|
||||
flexbox: "no-2009",
|
||||
},
|
||||
stage: 2
|
||||
})
|
||||
]
|
||||
}
|
||||
},
|
||||
"sass-loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.ts(x)?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
"awesome-typescript-loader"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [
|
||||
".ts",
|
||||
".js"
|
||||
]
|
||||
},
|
||||
devServer: {
|
||||
contentBase: "./dist",
|
||||
watchContentBase: true
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
Загрузка…
Ссылка в новой задаче