Skip to content

Commit

Permalink
feat: add an icon as HTML string
Browse files Browse the repository at this point in the history
Add a new property for MenuItem to display an icon as an HTML string.
The HTML will be sanitized internally using DOMPurify.
  • Loading branch information
GeorgianStan committed Sep 20, 2022
1 parent 1cba691 commit c79054f
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 12 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
### Browser CDN

```html
<script src="https://unpkg.com/vanilla-context-menu@1.2.2/dist/vanilla-context-menu.js"></script>
<script src="https://unpkg.com/vanilla-context-menu@1.3.0/dist/vanilla-context-menu.js"></script>
```

Where `@1.2.2` is the version that you want to use.
Where `@1.3.0` is the version that you want to use.

Then anywhere in your JavaScript code you can access the library with `window.VanillaContextMenu` or simply `VanillaContextMenu`.

Expand Down Expand Up @@ -56,6 +56,7 @@ new VanillaContextMenu({
callback: pasteFunction,
iconClass: 'fa fa-scissors', // this only works if you have FontAwesome icons
},
{ label: 'Face', iconHTML: `<span class="material-icons">face</span>` // this only works if you have Google Material Icons icons },
],
});
```
Expand Down Expand Up @@ -88,7 +89,8 @@ type MenuItem = MenuOption | 'hr';
| Option | Required | Type | Default | Description |
|:-------------------:|:--------:|:---------:|:---------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| label | **yes** | string | undefined | Menu option label. |
| iconClass | no | string | undefined | This property can be used in order to display an optional icon. It presents the CSS classes that will be added for the `<i></i>` tag. |
| iconClass | no | string | undefined | This property can be used to display an optional icon. It presents the CSS classes that will be added for the `<i></i>` tag. |
| iconHTML | no | string | undefined | This property can be used to display an optional icon. It presents an HTML string that will be sanitized internally using [DOMPurify](https://www.npmjs.com/package/dompurify). |
| callback | **yes** | (ev:MouseEvent) => any | undefined | Callback to be executed. The parameter `ev` is the MouseEvent that occurred when the `contextmenu` event was triggered |
| preventCloseOnClick | no | boolean | false | If this variable is `true`, then the context menu will not close when this menu option is clicked. A value set for this option, either `true` or `false` will override the global one. |
Expand Down
8 changes: 8 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>

<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">


<style>
html,
body {
Expand Down Expand Up @@ -77,9 +81,13 @@
label: 'Option 2',
callback: myFunction,
preventCloseOnClick: false,
// Font Awesome Icon
iconClass: 'fa fa-scissors',
},
// Bootstrap Icon
{ label: 'Option 3', iconClass: 'glyphicon glyphicon-cloud' },
// Google Material Icon
{ label: 'Option 4', iconHTML: `<span class="material-icons">face</span>` },
],
customThemeClass: 'context-menu-orange-theme',
customClass: 'custom-context-menu-cls',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vanilla-context-menu",
"version": "1.2.2",
"version": "1.3.0",
"description": "Easily create context menus using vanilla JavaScript and integrate them in any web application",
"main": "./dist/vanilla-context-menu.js",
"types": "./dist/index.d.ts",
Expand Down
4 changes: 4 additions & 0 deletions src/@types/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ export interface Options extends ConfigurableOptions, CoreOptions {}
export interface MenuOption {
label: string;
callback: (ev: MouseEvent) => any;
/**
* @deprecated This property was replaced by the new iconHTML property
*/
iconClass: string;
iconHTML:string;
preventCloseOnClick?: boolean; // default will be false - individual value for each item (it will over write the global value if any)
}

Expand Down
7 changes: 5 additions & 2 deletions src/index.pug
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ div(class=`${style['context-menu']}`)
hr
else
div
if item.iconClass
i(class=`${item.iconClass}`)
span(class=`${style['menu-item-icon']}`)
if item.iconClass
i(class=`${item.iconClass}`)
if item.iconHTML
!= item.iconHTML
span=item.label
12 changes: 10 additions & 2 deletions src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,17 @@
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
}

i {
margin-right: 5px;
.menu-item-icon {
display: flex;
align-items: center;
justify-content: center;
& > * {
margin: 0;
padding: 0;
font-size: 16px;
}
}
}
32 changes: 28 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* * Dependencies
*/
import {sanitize} from 'dompurify';

/**
* * Base & Template * Style
*/
Expand Down Expand Up @@ -221,16 +226,28 @@ export default class VanillaContextMenu {
constructor(configurableOptions: ConfigurableOptions) {
this.updateOptions(configurableOptions);

this.#state.menuItems = this.#options.menuItems;

// bind the required event listeners
this.#options.scope.oncontextmenu = this.#onShowContextMenu;

// add a click event listener to create a modal effect for the context menu and close it if the user clicks outside of it
document.addEventListener('click', this.#onDocumentClick);
}

// Public methods (API)
/**
* Sanitize the HTML content for menu icons
* @param menuItems
*/
#sanitizeMenuIcons = (menuItems: MenuItem[]): MenuItem[] =>
menuItems.map((item) => {
typeof item === 'object' &&
item.hasOwnProperty('iconHTML') &&
// TODO replace DOMPurify with Sanitize API when it will be supported https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API
(item.iconHTML = sanitize(item.iconHTML));

return item;
});

// Public methods (API)

/**
* Remove all the event listeners that were registered for this feature
Expand All @@ -241,9 +258,16 @@ export default class VanillaContextMenu {
}

updateOptions(configurableOptions: Partial<ConfigurableOptions>): void {
const sanitizedMenuItems = this.#sanitizeMenuIcons(
configurableOptions.menuItems,
);

// extend default options and bind the menu items inside the state for pug template
Object.assign(this.#options, this.#defaultOptions);
Object.assign(this.#options, configurableOptions);
Object.assign(this.#options, {
...configurableOptions,
menuItems: sanitizedMenuItems,
});
Object.assign(this.#options, this.#coreOptions);

this.#state.menuItems = this.#options.menuItems;
Expand Down

0 comments on commit c79054f

Please sign in to comment.