consent-banner/README.md

402 строки
15 KiB
Markdown
Исходник Постоянная ссылка Обычный вид История

# Consent Banner
## Overview
2020-04-17 06:26:18 +03:00
2020-07-01 00:51:46 +03:00
Consent banner is the library which will generate a banner at the specified position for asking the cookie preferences.
2022-02-14 01:46:57 +03:00
It contains three buttons, `accept all`, `reject 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.
2020-07-01 00:51:46 +03:00
2020-04-17 06:26:18 +03:00
## 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
2020-04-17 06:26:18 +03:00
```
## Testing
```sh
npm run test
2020-07-01 00:51:46 +03:00
```
## 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 = {
2020-08-26 22:57:41 +03:00
bannerMessageHtml: "We use optional cookies to provide... read <a href='link'>here</a>.",
acceptAllLabel: "Accept all",
2022-02-14 01:46:57 +03:00
rejectAllLabel: "Reject all",
2020-08-26 22:57:41 +03:00
moreInfoLabel: "More info",
preferencesDialogCloseLabel: "Close",
preferencesDialogTitle: "Manage cookie preferences",
preferencesDialogDescHtml: "Most Microsoft sites...",
acceptLabel: "Accept",
rejectLabel: "Reject",
saveLabel: "Save changes",
resetLabel: "Reset all"
2020-07-01 00:51:46 +03:00
};
let callBack = function(obj: any) { console.log(obj); };
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
// If you want to set 'nonce: test1' in style tag, add "stylesNonce: 'test1'"
let options: IOptions = {
textResources: textResources,
initialTheme: "dark",
stylesNonce: "test1"
};
2020-07-01 00:51:46 +03:00
2020-08-26 22:57:41 +03:00
let cc = new ConsentControl("app", "en", callBack, cookieCategories, options);
let cookieCategoriePreferences: ICookieCategoriesPreferences = {
"c1": undefined,
"c2": false,
"c3": true
};
2020-07-01 00:51:46 +03:00
2020-08-26 22:57:41 +03:00
// Show a banner with dark theme
2020-07-01 00:51:46 +03:00
cc.showBanner(cookieCategoriePreferences);
2020-08-26 22:57:41 +03:00
let theme: ITheme = {
"close-button-color": "#000080",
"secondary-button-disabled-opacity": "1",
"secondary-button-hover-shadow": "none",
"primary-button-disabled-opacity": "0.65",
"primary-button-hover-border": "none",
"primary-button-disabled-border": "1px double #3CB371",
"primary-button-hover-shadow": "2px 5px 7px #A12A29",
"banner-background-color": "#BA5583",
"dialog-background-color": "#32CD32",
"primary-button-color": "#4B30AE",
"text-color": "#800000",
"secondary-button-color": "#00FA9A",
"secondary-button-disabled-color": "#7B68EE",
"secondary-button-border": "1px dashed #969696",
}
// Create a new theme, named "medium"
cc.createTheme("medium", theme);
// Apply the "medium" theme
cc.applyTheme("medium");
2020-07-01 00:51:46 +03:00
```
## Developer Guide
2020-08-26 22:57:41 +03:00
`ConsentControl` consists of 2 main elements: **Banner** and **Preferences Dialog**. Use `containerElementOrId`, `culture`, `onPreferencesChanged`, `cookieCategories`, `options` to create an instance. `culture` will be used to determine the direction of the banner and preferences dialog.
2020-07-01 00:51:46 +03:00
```JavaScript
var cc = new ConsentControl(
2020-08-26 22:57:41 +03:00
// here the banner will be inserted, can be HTMLElement or element id
containerElementOrId: string | HTMLElement,
// 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)
culture: string,
2022-02-14 01:46:57 +03:00
// callback function, called on preferences changes (via "Accept All", "Reject All" or "Save changes"),
2020-08-26 22:57:41 +03:00
// must pass cookieCategoriePreferences, see ICookieCategoriesPreferences in Data types
onPreferencesChanged: (cookieCategoriesPreferences: ICookieCategoriesPreferences) => void,
// optional, see ICookieCategory in Data types
cookieCategories?: ICookieCategory[],
// optional, see IOptions in Data types
options?: IOptions
2020-07-01 00:51:46 +03:00
);
```
2020-08-26 22:57:41 +03:00
+ `setTextResources(textResources: ITextResources)` can be used to set the texts.
+ `createTheme(name: string, theme: ITheme)` can be used to create the new theme. `name` is the name of this new theme, which can be used by `applyTheme(themeName: string)`. `theme` is the new theme object.
`ConsentControl` consists of three built in themes, `light`, `dark`, and `high-contrast`. `dark` and `high-contrast` themes are from [Microsoft Docs](https://docs.microsoft.com/en-us/).
2020-07-01 04:23:41 +03:00
2020-08-26 22:57:41 +03:00
+ You can apply the theme manually by using `applyTheme(themeName: string)`. `themeName` is the name of the theme which you want to apply.
If you want to apply a new theme, you need to call `createTheme(name: string, theme: ITheme)` first, and then call `applyTheme(themeName: string)`
```JavaScript
let theme: ITheme = {
"close-button-color": "#000080",
"secondary-button-disabled-opacity": "1",
"secondary-button-hover-shadow": "none",
"primary-button-disabled-opacity": "0.65",
"primary-button-hover-border": "none",
"primary-button-disabled-border": "1px double #3CB371",
"primary-button-hover-shadow": "2px 5px 7px #A12A29",
"banner-background-color": "#BA5583",
"dialog-background-color": "#32CD32",
"primary-button-color": "#4B30AE",
"text-color": "#800000",
"secondary-button-color": "#00FA9A",
"secondary-button-disabled-color": "#7B68EE",
"secondary-button-border": "1px dashed #969696",
}
// Create a new theme, named "medium"
cc.createTheme("medium", theme);
// Apply the "medium" theme
cc.applyTheme("medium");
```
If the name of theme is not in the themes collections, it will throw an error. `new Error("Theme not found error")`
2020-08-26 22:57:41 +03:00
+ `setContainerElement(containerElementOrId: string | HTMLElement)` can be used to set the container element for the banner and preferences dialog.
2020-07-01 04:23:41 +03:00
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.
2020-07-01 04:23:41 +03:00
```JavaScript
cc.setContainerElement("app");
```
2020-07-01 04:23:41 +03:00
or
2020-07-01 04:23:41 +03:00
```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")`
2020-08-26 22:57:41 +03:00
+ `getContainerElement()` will return the current container element.
2020-07-01 04:23:41 +03:00
2020-08-26 22:57:41 +03:00
+ 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");
2020-07-01 04:23:41 +03:00
// 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();
```
2020-08-26 22:57:41 +03:00
+ `getDirection()` will return the current direction.
2020-07-01 04:23:41 +03:00
2020-07-01 00:51:46 +03:00
### Data types
2020-08-26 22:57:41 +03:00
There are six data types: `ICookieCategory`, `ITextResources`, `ICookieCategoriesPreferences`, `IOptions`, `IThemes`, and `ITheme`.
2020-07-01 00:51:46 +03:00
+ `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.
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
+ `IOptions` is the options for the banner. It contains four parts, `textResources`, `themes`, `initialTheme`, and `stylesNonce`.
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
+ `textResources` is the initial text resources for texts.
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
+ `themes` is a collections of themes that can be applied to the banner and preferences dialog.
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
+ `initialTheme` is the initial theme that you want to applied before you call `applyTheme(themeName: string)`.
+ `stylesNonce` is the `nonce` attribute for `<style>` tag.
The `nonce` attribute enables you to **whitelist** certain inline script and style elements, while avoiding use of the Content Security Policy ([CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)) unsafe-inline directive (which would allow all inline script/style), so that you still retain the key CSP feature of disallowing inline script/style in general. Also see [CSP: style-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src) for more information. If `stylesNonce` is undefined, the `nonce` attribute will not be added to `<style>` tag.
2020-08-26 22:57:41 +03:00
+ `IThemes` is a collections of themes. The properties names are the names of each themes, and the values are the theme objects.
2020-08-26 22:57:41 +03:00
+ `ITheme` is the theme object. It contains required properties and optional properties. Optional properties can be calculated by a built in method with required ones.
2020-07-01 00:51:46 +03:00
```TypeScript
// All categories should be replaced with the passed ones in the control
interface ICookieCategory {
id: string;
name: string;
descHtml: string;
2020-08-26 22:57:41 +03:00
// optional, prevents toggling the category.
// True only for categories like Essential cookies.
isUnswitchable?: boolean;
2020-07-01 00:51:46 +03:00
}
2020-08-26 22:57:41 +03:00
// only the passed text resources should be replaced in the control.
// If any string is not passed the control should keep the default value
2020-07-01 00:51:46 +03:00
interface ITextResources {
bannerMessageHtml?: string;
acceptAllLabel?: string;
2022-02-14 01:46:57 +03:00
rejectAllLabel?: string;
2020-07-01 00:51:46 +03:00
moreInfoLabel?: string;
preferencesDialogCloseLabel?: string;
preferencesDialogTitle?: string;
preferencesDialogDescHtml?: string;
acceptLabel?: string;
rejectLabel?: string;
saveLabel?: string;
resetLabel?: string;
}
interface ICookieCategoriesPreferences {
[key: string]: boolean | undefined;
}
2020-08-26 22:57:41 +03:00
interface IOptions {
textResources?: ITextResources;
themes?: IThemes;
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
initialTheme?: string;
stylesNonce?: string;
2020-08-26 22:57:41 +03:00
}
interface IThemes {
[key: string]: ITheme | undefined;
light?: ITheme;
dark?: ITheme;
"high-contrast"?: ITheme;
}
interface ITheme {
// All required properties
2020-08-26 22:57:41 +03:00
"close-button-color": string;
"secondary-button-disabled-opacity": string;
"secondary-button-hover-shadow": string;
"primary-button-disabled-opacity": string;
"primary-button-hover-border": string;
"primary-button-disabled-border": string;
"primary-button-hover-shadow": string;
"banner-background-color": string;
"dialog-background-color": string;
"primary-button-color": string;
"text-color": string;
"secondary-button-color": string;
"secondary-button-disabled-color": string;
"secondary-button-border": string;
// All optional properties
2020-08-26 22:57:41 +03:00
"background-color-between-page-and-dialog"?: string;
"dialog-border-color"?: string;
"hyperlink-font-color"?: string;
"secondary-button-hover-color"?: string;
"secondary-button-hover-border"?: string;
"secondary-button-disabled-border"?: string;
"secondary-button-focus-border-color"?: string;
"secondary-button-text-color"?: string;
"secondary-button-disabled-text-color"?: string;
"primary-button-hover-color"?: string;
"primary-button-disabled-color"?: string;
"primary-button-border"?: string;
"primary-button-focus-border-color"?: string;
"primary-button-text-color"?: string;
"primary-button-disabled-text-color"?: string;
"radio-button-border-color"?: string;
"radio-button-checked-background-color"?: string;
"radio-button-hover-border-color"?: string;
"radio-button-hover-background-color"?: string;
"radio-button-disabled-color"?: string;
"radio-button-disabled-border-color"?: string;
}
2020-07-01 00:51:46 +03:00
```
### Provided methods
+ Methods related to **banner**: `showBanner(cookieCategoriesPreferences: ICookieCategoriesPreferences)` and `hideBanner()`
+ Methods related to **Preferences Dialog**: `showPreferences(cookieCategoriesPreferences: ICookieCategoriesPreferences)` and `hidePreferences()`
2020-07-01 00:51:46 +03:00
Also see `ICookieCategoriesPreferences` in [Data types](#data-types)
2020-08-26 22:57:41 +03:00
2020-07-01 00:51:46 +03:00
```JavaScript
2020-08-26 22:57:41 +03:00
// 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.
2020-07-01 00:51:46 +03:00
cc.showBanner(
2020-08-26 22:57:41 +03:00
cookieCategoriesPreferences: ICookieCategoriesPreferences
2020-07-01 00:51:46 +03:00
);
// Hides the banner and the Preferences Dialog.
// Removes all HTML elements of the Consent Control from the DOM
2020-07-01 00:51:46 +03:00
cc.hideBanner();
2020-08-26 22:57:41 +03:00
// Shows Preferences Dialog. Leaves banner state unchanged.
Add nonce attribute to style tags and setNonceAttribute(...) method (#27) * Fix esc key in IE Instead of `event.key == 'Escape'` in Chrome or Firefox, IE used `event.key == 'Esc'`. * `showBanner(...)` only create banner. In previous version, `showBanner(...)` will create banner and hidden dialog. In the new version, `showBanner(...) will only create banner. When user clicks `More info` button, it will call `showPreference(...)` to create a dialog. When `onPreferencesDialogShowing()` is called, it will check the dialog is in the DOM or not. Since the only method to remove the dialog is `hidePreferencesDialog()`, and it will set `this.previousFocusElementBeforePopup = null;`, we use `this.previousFocusElementBeforePopup` to determine the dialog is in the DOM or not. If there is a dialog, we will not add event listener. * Add new test cases and update old ones * Add nonce to style tags and `setNonceAttribute(...)` method 1. Add nonce to all style tags 2. Add `setNonceAttribute(...)` method to set nonce attribute 3. Use `textContent` to replace `innerHTML` to change theme * Set style nonce in constructor 1. Add stylesNonce in IOptions 2. Add webpack-dev-server configuration for Content Security Policy 3. Set style nonce in constructor * Update `.d.ts` file and document 1. Add `stylesNonce` in interface `IOptions` and related methods 2. Update `showPreferences(...)` * Update webpack.production.config.js and bump npm version * Add explanation in stylesNonce * Simplify webpack.config.js Use webpack-merge to simplify webpack configuration file. webpack.common.js is the common part in developmment and production. Use webpack.dev.js and webpack.prod.js to insert the development and production specific configuration. * Update `nonce` attribute in style tag Since loaders are stateless, we need to reload it if we want to change it. Instead, we get the styles contents and remove the blocked style element with style element id. With the styles contents and passed `nonce`, we can create the new style element that will not be blocked. If we removed `style-loader` and loaded style element by ourselves, the actual styles contents will be `styles[0][1]`. Reference: https://webpack.js.org/contribute/writing-a-loader/ https://webpack.js.org/guides/hot-module-replacement/ * Use `style-loader` to `inject` styles and `nonce` to `<style>` * Only add `nonce` to `<style>` if it is not empty 1. Only add `nonce` to `<style>` when options.stylesNonce is not empty 2. Remove private methods in `.d.ts` file * Update Jest config and test cases The new file applied in configuration is based on `identity-obj-proxy`. styles.locals.bannerBody -> bannerBody Check: https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js * Update test cases Co-authored-by: Bill Chou (Zen3 Infosolutions America Inc) <v-tincho@microsoft.com>
2020-10-06 00:15:09 +03:00
// It is used to insert HTML code for the preferences dialog.
2020-07-01 00:51:46 +03:00
cc.showPreferences(
2020-08-26 22:57:41 +03:00
cookieCategoriesPreferences: ICookieCategoriesPreferences
2020-07-01 00:51:46 +03:00
);
2020-08-26 22:57:41 +03:00
// Hides Preferences Dialog. Removes all HTML elements of the Preferences Dialog from the DOM.
// Leaves banner state unchanged
2020-07-01 00:51:46 +03:00
cc.hidePreferences();
```
### Custom settings
1. Change the width of buttons in banner: Change `$bannerBtnWidth` in `styles.scss`
2. `webpack.dev.js` file is for development purpose, and `webpack.prod.js` is for production. `webpack.common.js` is the common parts in both `webpack.dev.js` and `webpack.prod.js`. Both `webpack.dev.js` and `webpack.prod.js` require `webpack.common.js`. There are two differences between `webpack.dev.js` and `webpack.prod.js`. `localIdentName` in `use/options/modules` under `module/rules` only uses hash in production mode. Only development mode contains `devServer`. The `headers` in `devServer` can be used to set `CSP`. The default `nonce` is `test1`.
## 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
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.