https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.2.5/dist/iframemanager.js
https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.2.5/dist/iframemanager.css
using npm
:
npm i @orestbida/iframemanager
<html>
<head>
...
<link rel="stylesheet" href="https://github.com/orestbida/iframemanager/blob/main/iframemanager.css">
</head>
<body>
...
<script defer src="https://github.com/orestbida/iframemanager/raw/main/iframemanager.js"></script>
<body>
</html>
- Create a .js file (e.g. `app.js`) and import it in your html markup: ```html
... ``` - Configure iframemanager inside `app.js`: ```javascript (function(){ const im = iframemanager(); // Example with youtube embed im.run({ currLang: 'en', services : { youtube : { embedUrl: 'https://www.youtube-nocookie.com/embed/{data-id}', thumbnailUrl: 'https://i3.ytimg.com/vi/{data-id}/hqdefault.jpg', iframe : { allow : 'accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;' }, languages : { en : { notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of youtube.com.', loadBtn: 'Load video', loadAllBtn: "Don't ask again" } } } } }); })(); ``````html
... ```data-service
and data-id
attributes:<div data-service="youtube" data-id="<video-id>"></div>
All available options for the <div>
element:
<div
data-service="<service-name>"
data-id="<resource-id>"
data-params="<iframe-query-parameters>"
data-thumbnail="<path-to-image>"
data-autoscale
data-ratio="<x:y>">
</div>
data-service
: [String, Required] name of the service (must also be defined in the config. object)data-id
: [String, Required] unique id of the resource (example: video id)data-title
: [String] notice titledata-params
: [String] iframe query parametersdata-thumbnail
: [String] path to custom thumbnaildata-ratio
: [String] custom aspect ratio (Available values.)[v1.1.0]data-autoscale
: specify for responsive iframe (fill parent width + scale proportionally)data-widget
: ignore the default aspect ratio; specify when implementing a custom widget with explicit width and height (twitter, facebook, instagram ...)[v1.2.0]iframe
elementYou can set any attribute by using the following syntax:
data-iframe-<attribute>
[String] note: replace <attribute>
with a valid attribute name. [v1.1.0]Example:
<div
data-service="youtube"
data-id="5b35haQV7tU"
data-autoscale
data-iframe-id="myYoutubeEmbed"
data-iframe-loading="lazy"
data-iframe-frameborder="0">
</div>
All available options for the config. object:
{
currLang: 'en', // current language of the notice (must also be defined in the "languages" object below)
autoLang: false, // if enabled => use current client's browser language
// instead of currLang [OPTIONAL]
// callback fired when state changes (a new service is accepted/rejected)
onChange: ({changedServices, eventSource}) => {
// changedServices: string[]
// eventSource.type: 'api' | 'click'
// eventSource.service: string
// eventSource.action: 'accept' | 'reject'
},
services : {
myservice : {
embedUrl: 'https://<myservice_embed_url>',
// set valid url for automatic thumbnails [OPTIONAL]
thumbnailUrl: 'https://<myservice_embed_thumbnail_url>',
// global iframe settings (apply to all iframes relative to current service) [OPTIONAL]
iframe: {
allow: 'fullscreen', // iframe's allow attribute
params: 'mute=1&start=21', // iframe's url query parameters
// function run for each iframe configured with current service
onload: (dataId, setThumbnail) => {
console.log(`loaded iframe with data-id=${dataId}`);
}
},
// cookie is set if the current service is accepted
cookie: {
name: 'cc_youtube', // cookie name
path: '/', // cookie path [OPTIONAL]
samesite: 'lax', // cookie samesite [OPTIONAL]
domain: location.hostname // cookie domain [OPTIONAL]
},
languages: {
en: {
notice: 'Html <b>notice</b> message',
loadBtn: 'Load video', // Load only current iframe
loadAllBtn: "Don't ask again" // Load all iframes configured with this service + set cookie
}
}
},
anotherservice: {
// ...
}
}
}
Any other property specified inside the iframe
object, will be set directly to the iframe
element as attribute.
Example: add frameborder
and style
attributes:
{
// ...
services: {
myservice: {
// ...
iframe: {
// ...
frameborder: '0',
style: 'border: 4px solid red;'
}
}
}
}
Note: thumbnailUrl
can be static string, dynamic string or a function:
static string
: "https://path_to_image/image.png"dynamic string
: "https://myservice_embed_url/{data-id}"function
:
thumbnailUrl: (dataId, setThumbnail) => {
// fetch thumbnail url here based on dataId of the current element ...
let url = 'fetched_url';
// pass obtained url to the setThumbnail function
setThumbnail(url);
}
Some services (e.g. twitter) have their own markup and API to generate the iframe.
Note: this is an example with twitter's widget. Each widget/service will have a slightly different implementation.
Place the markup inside a special data-placeholder
div. Remove any script
tag that comes with the markup. Example:
<div
data-service="twitter"
data-widget
style="width: 300px; height: 501px"
>
<div data-placeholder>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Sunsets don't get much better than this one over <a href="https://twitter.com/GrandTetonNPS?ref_src=twsrc%5Etfw">@GrandTetonNPS</a>. <a href="https://twitter.com/hashtag/nature?src=hash&ref_src=twsrc%5Etfw">#nature</a> <a href="https://twitter.com/hashtag/sunset?src=hash&ref_src=twsrc%5Etfw">#sunset</a> <a href="http://t.co/YuKy2rcjyU">pic.twitter.com/YuKy2rcjyU</a></p>— US Department of the Interior (@Interior) <a href="https://twitter.com/Interior/status/463440424141459456?ref_src=twsrc%5Etfw">May 5, 2014</a></blockquote>
</div>
</div>
Create a new service and dynamically load and initialize the widget inside the onAccept
callback:
im.run({
services: {
twitter: {
onAccept: async (div, setIframe) => {
// Using cookieconsent v3
await CookieConsent.loadScript('https://platform.twitter.com/widgets.js');
// Make sure the "window.twttr" property exists
await im.childExists({childProperty: 'twttr'}) && await twttr.widgets.load(div);
// Make sure the "iframe" element exists
await im.childExists({parent: div}) && setIframe(div.querySelector('iframe'));
},
onReject: (iframe) => {
iframe && iframe.parentElement.remove();
}
}
}
})
It is highly recommended to set a fixed width
and height
to the main data-service
div, to avoid the (awful) content jump effect when the iframe is loaded.
You can set a placeholder visible only if javascript is disabled via a special div:
<div data-placeholder data-visible></div>
Example:
<div
data-service="youtube"
data-id="5b35haQV7tU"
data-autoscale>
<div data-placeholder data-visible>
<p>I'm visible only if js is disabled</p>
</div>
</div>
The plugin exposes the following methods:
.run(<config_object>)
.acceptService(<service_name>)
.rejectService(<service_name>)
.getState()
[v1.2.0+].getConfig()
[v1.2.0+]Example usage:
// accept specific service only
im.acceptService('youtube');
// accept all services (for example if user has given full consent to cookies)
im.acceptService('all');
// reject specific service
im.rejectService('youtube');
// reject all services (for example when user opts out of cookies)
im.rejectService('all');
// get entire config object
const config = im.getConfig();
// get current state (enabled/disabled services)
const state = im.getState();
// state.services: Map<string, boolean>
// state.acceptedServices: string[]
Both acceptService
and rejectService
work the same way:
```javascript im.run({ currLang: 'en', services: { youtube: { embedUrl: 'https://www.youtube-nocookie.com/embed/{data-id}', thumbnailUrl: 'https://i3.ytimg.com/vi/{data-id}/hqdefault.jpg', iframe: { allow: 'accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;', }, languages: { en: { notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of youtube.com.', loadBtn: 'Load video', loadAllBtn: "Don't ask again" } } } } }); ``` Example: ```html
``````javascript im.run({ currLang: 'en', services: { dailymotion: { embedUrl: 'https://www.dailymotion.com/embed/video/{data-id}', thumbnailUrl: async (dataId, setThumbnail) => { // Use dailymotion's API to fetch the thumbnail const url = `https://api.dailymotion.com/video/${dataId}?fields=thumbnail_large_url`; const response = await (await fetch(url)).json(); const thumbnailUlr = response?.thumbnail_large_url; thumbnailUlr && setThumbnail(thumbnailUlr); }, iframe: { allow: 'accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;', }, languages: { en: { notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of dailymotion.com.', loadBtn: 'Load video', loadAllBtn: "Don't ask again" } } } } }); ```
```javascript im.run({ currLang: 'en', services: { vimeo: { embedUrl: 'https://player.vimeo.com/video/{data-id}', iframe: { allow : 'fullscreen; picture-in-picture, allowfullscreen;', }, thumbnailUrl: async (dataId, setThumbnail) => { const url = `https://vimeo.com/api/v2/video/${dataId}.json`; const response = await (await fetch(url)).json(); const thumbnailUrl = response[0]?.thumbnail_large; thumbnailUrl && setThumbnail(thumbnailUrl); }, languages: { en: { notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of vimeo.com.', loadBtn: 'Load video', loadAllBtn: "Don't ask again" } } } } }); ```
```javascript im.run({ currLang: 'en', services: { twitch: { embedUrl: `https://player.twitch.tv/?{data-id}&parent=${location.hostname}`, iframe: { allow: 'accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;', }, languages: { en: { notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of twitch.com.', loadBtn: 'Load stream', loadAllBtn: "Don't ask again" } } } } }); ```
-
```javascript
im.run({
currLang: 'en',
services: {
googlemaps: {
embedUrl: 'https://www.google.com/maps/embed/v1/place?key=API_KEY&q={data-id}',
iframe: {
allow: 'picture-in-picture; fullscreen;'
},
languages: {
en: {
notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of Google Maps.',
loadBtn: 'Load map',
loadAllBtn: "Don't ask again"
}
}
}
}
});
```
Example:
```html
With API key
```javascript im.run({ currLang: 'en', services : { googlemaps : { embedUrl: 'https://www.google.com/maps/embed?pb={data-id}', iframe: { allow : 'picture-in-picture; fullscreen;' }, languages : { en : { notice: 'This content is hosted by a third party. By showing the external content you accept the terms and conditions of Google Maps.', loadBtn: 'Load map', loadAllBtn: "Don't ask again" } } } } }); ``` Example usage: ```html
```You can use the onChange
callback to detect when an iframe is loaded by the loadAllBtn
button click event and notify CookieConsent to also update its state.
Example:
im.run({
currLang: 'en',
onChange: ({changedServices, eventSource}) => {
if(eventSource.type === 'click') {
// Retrieve all accepted services:
// const allAcceptedServices = im.getState().acceptedServices;
/**
* Retrieve array of already accepted services
* and add the new service
*/
const servicesToAccept = [
...CookieConsent.getUserPreferences().acceptedServices['analytics'], //cookieconsent v3
...changedServices
];
CookieConsent.acceptService(servicesToAccept, 'analytics');
}
},
services: {
// ...
}
});
Note: the above example assumes that all services belong to the analytics
category.
data-ratio
Horizontal aspect ratio:
1:1
, 2:1
, 3:2
, 5:2
, 4:3
, 16:9
, 16:10
, 20:9
, 21:9
Vertical aspect ratio:
9:16
, 9:20
Distributed under the MIT License. See LICENSE for more information.
Not all services (example: twitch) allow automatic/easy thumbnail fetch.