cloudinary-video-player 1.6.2-edge.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +4 -0
- package/.snyk +19 -0
- package/.travis.yml +8 -0
- package/CHANGELOG.md +329 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/dist/cld-video-player.css +2110 -0
- package/dist/cld-video-player.js +5249 -0
- package/dist/cld-video-player.light.css +1766 -0
- package/dist/cld-video-player.light.js +1399 -0
- package/dist/cld-video-player.light.min.css +1 -0
- package/dist/cld-video-player.light.min.js +2 -0
- package/dist/cld-video-player.light.min.js.LICENSE.txt +23 -0
- package/dist/cld-video-player.min.css +1 -0
- package/dist/cld-video-player.min.js +2 -0
- package/dist/cld-video-player.min.js.LICENSE.txt +26 -0
- package/dist/fonts/cloudinary_icon_for_black_bg.svg +69 -0
- package/dist/fonts/cloudinary_icon_for_white_bg.svg +69 -0
- package/docs/360.html +102 -0
- package/docs/_template.html +93 -0
- package/docs/adaptive-streaming.html +297 -0
- package/docs/analytics.html +140 -0
- package/docs/api.html +302 -0
- package/docs/audio.html +136 -0
- package/docs/autoplay-fallback.html +138 -0
- package/docs/autoplay-on-scroll.html +107 -0
- package/docs/codec-fallback.html +158 -0
- package/docs/colors.html +135 -0
- package/docs/components.html +284 -0
- package/docs/custom-cld-errors.html +134 -0
- package/docs/floating-player.html +98 -0
- package/docs/fluid.html +117 -0
- package/docs/force-hls-subtitles-ios.html +159 -0
- package/docs/index.html +83 -0
- package/docs/interaction-area.html +398 -0
- package/docs/live-customer.html +128 -0
- package/docs/multiple-players.html +125 -0
- package/docs/playlist-by-tag-cap.html +182 -0
- package/docs/playlist-by-tag.html +133 -0
- package/docs/playlist.html +133 -0
- package/docs/poster.html +155 -0
- package/docs/raw-url.html +104 -0
- package/docs/recommendations.html +155 -0
- package/docs/scripts.js +156 -0
- package/docs/seek-thumbs.html +90 -0
- package/docs/shoppable.html +335 -0
- package/docs/subtitles-and-captions.html +267 -0
- package/docs/transformations.html +171 -0
- package/docs/ui-config.html +108 -0
- package/docs/vast-vpaid.html +149 -0
- package/env.example.js +6 -0
- package/env.js +6 -0
- package/jest-puppeteer.config.js +14 -0
- package/jest.config.js +196 -0
- package/package.json +99 -0
- package/sandbox.config.json +3 -0
- package/setupJest.js +1 -0
- package/src/assets/fonts/VideoJS.svg +120 -0
- package/src/assets/fonts/VideoJS.ttf +0 -0
- package/src/assets/fonts/VideoJS.woff +0 -0
- package/src/assets/fonts/icons.json +120 -0
- package/src/assets/icons/cloudinary_icon_for_black_bg.svg +69 -0
- package/src/assets/icons/cloudinary_icon_for_white_bg.svg +69 -0
- package/src/assets/icons/cloudinary_logo_for_dark_bg.svg +188 -0
- package/src/assets/icons/cloudinary_logo_for_white_bg.svg +188 -0
- package/src/assets/icons/info-circle.svg +17 -0
- package/src/assets/styles/ads-label.scss +16 -0
- package/src/assets/styles/components/interaction-areas.scss +158 -0
- package/src/assets/styles/components/playlist.scss +213 -0
- package/src/assets/styles/components/themedButton.scss +48 -0
- package/src/assets/styles/components/thumbnail.scss +94 -0
- package/src/assets/styles/components/title-bar.scss +67 -0
- package/src/assets/styles/components/triangle-volume-bar.scss +52 -0
- package/src/assets/styles/icons.scss +257 -0
- package/src/assets/styles/main.scss +324 -0
- package/src/assets/styles/mixins/aspect-ratio.scss +16 -0
- package/src/assets/styles/mixins/disable-transition.scss +3 -0
- package/src/assets/styles/mixins/mixins.scss +5 -0
- package/src/assets/styles/mixins/skin.scss +64 -0
- package/src/assets/styles/variables.scss +2 -0
- package/src/assets/styles/videojs-ima.scss +252 -0
- package/src/components/component-utils.js +20 -0
- package/src/components/index.js +21 -0
- package/src/components/interaction-area/interaction-area.const.js +30 -0
- package/src/components/interaction-area/interaction-area.service.js +223 -0
- package/src/components/interaction-area/interaction-area.utils.js +236 -0
- package/src/components/jumpButtons/jump-10-minus.js +21 -0
- package/src/components/jumpButtons/jump-10-plus.js +20 -0
- package/src/components/logoButton/logo-button.const.js +3 -0
- package/src/components/logoButton/logo-button.js +30 -0
- package/src/components/logoButton/logo-button.scss +15 -0
- package/src/components/playlist/components/playlist-button.js +34 -0
- package/src/components/playlist/components/playlist-next-button.js +18 -0
- package/src/components/playlist/components/playlist-previous-button.js +18 -0
- package/src/components/playlist/components/playlist.js +5 -0
- package/src/components/playlist/components/playlist.scss +15 -0
- package/src/components/playlist/components/upcoming-video-overlay.js +149 -0
- package/src/components/playlist/components/upcoming-video-overlay.scss +86 -0
- package/src/components/playlist/layout/playlist-layout-custom.js +21 -0
- package/src/components/playlist/layout/playlist-layout-horizontal.js +16 -0
- package/src/components/playlist/layout/playlist-layout-vertical.js +19 -0
- package/src/components/playlist/layout/playlist-layout.js +110 -0
- package/src/components/playlist/panel/playlist-panel-item.js +86 -0
- package/src/components/playlist/panel/playlist-panel.js +92 -0
- package/src/components/playlist/playlist-widget.js +119 -0
- package/src/components/playlist/playlist.const.js +14 -0
- package/src/components/playlist/playlist.js +413 -0
- package/src/components/playlist/thumbnail/thumbnail.js +69 -0
- package/src/components/progress-control-events-blocker/progress-control-events-blocker.js +17 -0
- package/src/components/qualitySelector/quality-selector.scss +10 -0
- package/src/components/qualitySelector/qualitySelector.js +152 -0
- package/src/components/recommendations-overlay/index.js +3 -0
- package/src/components/recommendations-overlay/recommendations-overlay-content.js +57 -0
- package/src/components/recommendations-overlay/recommendations-overlay-hide-button.js +18 -0
- package/src/components/recommendations-overlay/recommendations-overlay-item.js +35 -0
- package/src/components/recommendations-overlay/recommendations-overlay-primary-item.js +81 -0
- package/src/components/recommendations-overlay/recommendations-overlay-secondary-item.js +48 -0
- package/src/components/recommendations-overlay/recommendations-overlay-secondary-items-container.js +35 -0
- package/src/components/recommendations-overlay/recommendations-overlay.js +94 -0
- package/src/components/recommendations-overlay/recommendations-overlay.scss +182 -0
- package/src/components/shoppable-bar/layout/bar-layout.js +111 -0
- package/src/components/shoppable-bar/layout/shoppable-panel-toggle.js +64 -0
- package/src/components/shoppable-bar/layout/shoppable-products-overlay.js +87 -0
- package/src/components/shoppable-bar/panel/shoppable-panel-item.js +105 -0
- package/src/components/shoppable-bar/panel/shoppable-panel.js +172 -0
- package/src/components/shoppable-bar/shoppable-post-widget.js +110 -0
- package/src/components/shoppable-bar/shoppable-widget.const.js +52 -0
- package/src/components/shoppable-bar/shoppable-widget.js +111 -0
- package/src/components/shoppable-bar/shoppable-widget.scss +359 -0
- package/src/components/themeButton/themedButton.const.js +3 -0
- package/src/components/themeButton/themedButton.js +25 -0
- package/src/components/title-bar/title-bar.js +79 -0
- package/src/config/defaults.js +25 -0
- package/src/extended-events.js +228 -0
- package/src/index.js +18 -0
- package/src/mixins/eventable.js +54 -0
- package/src/mixins/playlistable.js +106 -0
- package/src/plugins/analytics/index.js +245 -0
- package/src/plugins/autoplay-on-scroll/index.js +86 -0
- package/src/plugins/cloudinary/common.js +216 -0
- package/src/plugins/cloudinary/event-handler-registry.js +46 -0
- package/src/plugins/cloudinary/index.js +345 -0
- package/src/plugins/cloudinary/models/audio-source/audio-source.const.js +11 -0
- package/src/plugins/cloudinary/models/audio-source/audio-source.js +82 -0
- package/src/plugins/cloudinary/models/base-source.js +107 -0
- package/src/plugins/cloudinary/models/image-source.js +26 -0
- package/src/plugins/cloudinary/models/video-source/video-source.const.js +32 -0
- package/src/plugins/cloudinary/models/video-source/video-source.js +239 -0
- package/src/plugins/cloudinary/models/video-source/video-source.utils.js +57 -0
- package/src/plugins/colors/index.js +303 -0
- package/src/plugins/context-menu/components/context-menu-item.js +12 -0
- package/src/plugins/context-menu/components/context-menu.js +63 -0
- package/src/plugins/context-menu/context-menu.scss +30 -0
- package/src/plugins/context-menu/contextMenuContent.js +53 -0
- package/src/plugins/context-menu/index.js +134 -0
- package/src/plugins/dash/index.js +26 -0
- package/src/plugins/dash/setup-audio-tracks.js +112 -0
- package/src/plugins/dash/setup-text-tracks.js +195 -0
- package/src/plugins/dash/videojs-dash.js +372 -0
- package/src/plugins/floating-player/floating-player.scss +74 -0
- package/src/plugins/floating-player/index.js +129 -0
- package/src/plugins/ima/index.js +1775 -0
- package/src/plugins/index.js +31 -0
- package/src/plugins/interactive-plugin/index.js +10 -0
- package/src/plugins/videojs-http-source-selector/components/SourceMenuButton.js +98 -0
- package/src/plugins/videojs-http-source-selector/components/SourceMenuItem.js +52 -0
- package/src/plugins/videojs-http-source-selector/plugin.js +82 -0
- package/src/plugins/videojs-http-source-selector/plugin.scss +9 -0
- package/src/plugins/vtt-thumbnails/index.js +526 -0
- package/src/plugins/vtt-thumbnails/vtt-thumbnails.scss +29 -0
- package/src/utils/api.js +32 -0
- package/src/utils/apply-with-props.js +32 -0
- package/src/utils/array.js +22 -0
- package/src/utils/assign.js +27 -0
- package/src/utils/attributes-normalizer.js +72 -0
- package/src/utils/cloudinary.js +165 -0
- package/src/utils/css-prefix.js +43 -0
- package/src/utils/dom.js +74 -0
- package/src/utils/find.js +28 -0
- package/src/utils/fontFace.js +25 -0
- package/src/utils/groupBy.js +12 -0
- package/src/utils/index.js +29 -0
- package/src/utils/matches.js +11 -0
- package/src/utils/mixin.js +5 -0
- package/src/utils/object.js +26 -0
- package/src/utils/playButton.js +9 -0
- package/src/utils/positioning.js +78 -0
- package/src/utils/querystring.js +12 -0
- package/src/utils/slicing.js +21 -0
- package/src/utils/string.js +15 -0
- package/src/utils/throttle.js +30 -0
- package/src/utils/time.js +77 -0
- package/src/utils/type-inference.js +35 -0
- package/src/validators/validators-functions.js +48 -0
- package/src/validators/validators-types.js +78 -0
- package/src/validators/validators.js +110 -0
- package/src/video-player.const.js +68 -0
- package/src/video-player.js +761 -0
- package/src/video-player.utils.js +123 -0
- package/test/adaptive-streaming.test.js +38 -0
- package/test/ads.test.js +35 -0
- package/test/analytics.test.js +111 -0
- package/test/api.test.js +111 -0
- package/test/autoplay.scroll.test.js +23 -0
- package/test/basic-ui.test.js +59 -0
- package/test/colors.test.js +58 -0
- package/test/components.test.js +21 -0
- package/test/custom-error.test.js +24 -0
- package/test/fluid.test.js +36 -0
- package/test/isValidConfig.test.js +224 -0
- package/test/mocks/cloudinary-core-mock.js +0 -0
- package/test/mocks/styleMock.js +1 -0
- package/test/multiplayer.test.js +25 -0
- package/test/playlist.test.js +60 -0
- package/test/puppeteer/vp-env.js +19 -0
- package/test/recommendations.test.js +38 -0
- package/test/title-bar.test.js +28 -0
- package/test/ui-conf.test.js +49 -0
- package/test/unit/cloudinaryConfig.test.js +22 -0
- package/test/unit/cloudinaryUtils.test.js +53 -0
- package/test/unit/utils.test.js +27 -0
- package/test/unit/videoSource.test.js +454 -0
- package/tsconfig.json +15 -0
- package/types/video-player-tests.js +12 -0
- package/types/video-player-tests.ts +31 -0
- package/types/video-player.d.ts +570 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
import {
|
|
3
|
+
CLD_SPBL_TOGGLE_CLASS,
|
|
4
|
+
CLD_SPBL_TOGGLE_CUSTOM_ICON_CLASS,
|
|
5
|
+
CLD_SPBL_TOGGLE_ICON_CLASS,
|
|
6
|
+
CLOSE_ICON_CLASS,
|
|
7
|
+
ICON_CART_CLASS,
|
|
8
|
+
SHOPPABLE_ANIMATION_CLASS
|
|
9
|
+
} from '../shoppable-widget.const';
|
|
10
|
+
const dom = videojs.dom || videojs;
|
|
11
|
+
|
|
12
|
+
const ClickableComponent = videojs.getComponent('ClickableComponent');
|
|
13
|
+
|
|
14
|
+
class ShoppablePanelToggle extends ClickableComponent {
|
|
15
|
+
|
|
16
|
+
constructor(player, options) {
|
|
17
|
+
super(player, options);
|
|
18
|
+
this.options_ = options;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
handleClick(event) {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
this.options_.clickHandler();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
createEl() {
|
|
28
|
+
let iconProps = {};
|
|
29
|
+
let iconAttrs = {};
|
|
30
|
+
if (this.options_.toggleIcon) {
|
|
31
|
+
iconProps = {
|
|
32
|
+
className: `${CLD_SPBL_TOGGLE_ICON_CLASS} ${CLD_SPBL_TOGGLE_CUSTOM_ICON_CLASS} ${CLOSE_ICON_CLASS}`
|
|
33
|
+
};
|
|
34
|
+
iconAttrs = {
|
|
35
|
+
style: `background-image: url(${this.options_.toggleIcon})`
|
|
36
|
+
};
|
|
37
|
+
} else {
|
|
38
|
+
iconProps = {
|
|
39
|
+
className: `${CLD_SPBL_TOGGLE_ICON_CLASS} ${ICON_CART_CLASS}`
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const icon = dom.createEl('span', iconProps, iconAttrs);
|
|
43
|
+
|
|
44
|
+
const el = super.createEl('a', {
|
|
45
|
+
className: `${CLD_SPBL_TOGGLE_CLASS} base-color-bg`
|
|
46
|
+
});
|
|
47
|
+
el.appendChild(icon);
|
|
48
|
+
|
|
49
|
+
this.player_.on('productBarMin', () => {
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
icon.classList.add(SHOPPABLE_ANIMATION_CLASS);
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
icon.classList.remove(SHOPPABLE_ANIMATION_CLASS);
|
|
54
|
+
}, 1000);
|
|
55
|
+
}, 500);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return el;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
videojs.registerComponent('shoppablePanelToggle', ShoppablePanelToggle);
|
|
63
|
+
|
|
64
|
+
export default ShoppablePanelToggle;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
const dom = videojs.dom || videojs;
|
|
3
|
+
import { parseTime } from 'utils/time';
|
|
4
|
+
import { find } from 'utils/find';
|
|
5
|
+
import {
|
|
6
|
+
SHOPPABLE_PANEL_HIDDEN_CLASS,
|
|
7
|
+
SHOPPABLE_PANEL_VISIBLE_CLASS,
|
|
8
|
+
SHOPPABLE_PRODUCTS_OVERLAY_CLASS
|
|
9
|
+
} from '../shoppable-widget.const';
|
|
10
|
+
|
|
11
|
+
const Component = videojs.getComponent('Component');
|
|
12
|
+
|
|
13
|
+
class ShoppableProductsOverlay extends Component {
|
|
14
|
+
|
|
15
|
+
constructor(player, options = {}) {
|
|
16
|
+
super(player, options);
|
|
17
|
+
this.options_ = options;
|
|
18
|
+
this.player_ = player;
|
|
19
|
+
|
|
20
|
+
this.player_.on('showProductsOverlay', () => {
|
|
21
|
+
this.renderProducts();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
this.dispose = () => {
|
|
25
|
+
this.layout_.dispose();
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
renderProducts() {
|
|
30
|
+
// Close products side-panel
|
|
31
|
+
this.player_.removeClass(SHOPPABLE_PANEL_VISIBLE_CLASS);
|
|
32
|
+
this.player_.addClass(SHOPPABLE_PANEL_HIDDEN_CLASS);
|
|
33
|
+
this.player_.addClass(SHOPPABLE_PRODUCTS_OVERLAY_CLASS);
|
|
34
|
+
|
|
35
|
+
this.layout_.innerHTML = '';
|
|
36
|
+
|
|
37
|
+
// Filter products with appearance on currentTime
|
|
38
|
+
const currentTime = this.player_.currentTime();
|
|
39
|
+
const currentProducts = this.options_.products.filter(product => product.hotspots && product.hotspots.some(a => parseTime(a.time) === currentTime));
|
|
40
|
+
|
|
41
|
+
currentProducts.forEach(product => {
|
|
42
|
+
const hotspot = find(product.hotspots, (hs) => parseTime(hs.time) === currentTime);
|
|
43
|
+
|
|
44
|
+
const productName = dom.createEl('div',
|
|
45
|
+
{ className: 'cld-spbl-product-hotspot-name' },
|
|
46
|
+
{},
|
|
47
|
+
product.productName
|
|
48
|
+
);
|
|
49
|
+
const productTooltip = dom.createEl('div',
|
|
50
|
+
{ className: 'cld-spbl-product-tooltip cld-spbl-product-tooltip-' + hotspot.tooltipPosition },
|
|
51
|
+
{},
|
|
52
|
+
productName
|
|
53
|
+
);
|
|
54
|
+
const productHotSpot = dom.createEl('a',
|
|
55
|
+
{
|
|
56
|
+
className: 'cld-spbl-product-hotspot accent-color-text',
|
|
57
|
+
href: hotspot.clickUrl,
|
|
58
|
+
target: '_blank'
|
|
59
|
+
},
|
|
60
|
+
{ style: 'left:' + hotspot.x + '; top:' + hotspot.y + ';' },
|
|
61
|
+
productTooltip
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
this.layout_.appendChild(productHotSpot);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Remove
|
|
68
|
+
this.player_.one('seeking', (e) => this.clearLayout(e));
|
|
69
|
+
this.player_.one('play', (e) => this.clearLayout(e));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
clearLayout() {
|
|
73
|
+
this.layout_.innerHTML = '';
|
|
74
|
+
this.player_.removeClass(SHOPPABLE_PRODUCTS_OVERLAY_CLASS);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
createEl() {
|
|
78
|
+
this.layout_ = dom.createEl('div', { className: 'cld-spbl-products-overlay' });
|
|
79
|
+
|
|
80
|
+
return this.layout_;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
videojs.registerComponent('ShoppableProductsOverlay', ShoppableProductsOverlay);
|
|
86
|
+
|
|
87
|
+
export default ShoppableProductsOverlay;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
import { elMatches } from 'utils/matches';
|
|
3
|
+
|
|
4
|
+
const ClickableComponent = videojs.getComponent('ClickableComponent');
|
|
5
|
+
const dom = videojs.dom || videojs;
|
|
6
|
+
import ImageSource from '../../../plugins/cloudinary/models/image-source';
|
|
7
|
+
import {
|
|
8
|
+
CLD_SPBL_IMAGE,
|
|
9
|
+
CLD_SPBL_ITEM,
|
|
10
|
+
SHOPPABLE_CLICK_ACTIONS, SHOPPABLE_HOVER_ACTIONS,
|
|
11
|
+
SHOPPABLE_WIDGET_RESPONSIVE_CLASS
|
|
12
|
+
} from '../shoppable-widget.const';
|
|
13
|
+
|
|
14
|
+
class ShoppablePanelItem extends ClickableComponent {
|
|
15
|
+
|
|
16
|
+
constructor(player, initOptions) {
|
|
17
|
+
super(player, initOptions);
|
|
18
|
+
this.options_ = initOptions;
|
|
19
|
+
this.isDragged = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
handleClick(event) {
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
event.stopPropagation();
|
|
25
|
+
|
|
26
|
+
if (!elMatches(this.el_, `.dragged .${CLD_SPBL_ITEM}`)) {
|
|
27
|
+
// Prevent click event if dragged
|
|
28
|
+
this.options_.clickHandler(event);
|
|
29
|
+
}
|
|
30
|
+
this.isDragged = false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getTitle() {
|
|
34
|
+
return this.options_.conf.title;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
createEl() {
|
|
38
|
+
const el = super.createEl('a', {
|
|
39
|
+
className: `${CLD_SPBL_ITEM} base-color-bg accent-color-text`,
|
|
40
|
+
href: '#'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
el.setAttribute('data-product-id', this.options_.conf.productId || '');
|
|
44
|
+
el.setAttribute('data-product-name', this.options_.conf.productName || '');
|
|
45
|
+
|
|
46
|
+
if (this.options_.conf.onHover) {
|
|
47
|
+
addOnHover(el, this.options_.conf.onHover, this.options_.item.cloudinaryConfig());
|
|
48
|
+
}
|
|
49
|
+
if (this.options_.conf.onClick) {
|
|
50
|
+
addOnClick(el, this.options_.conf.onClick);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const img = super.createEl('img',
|
|
54
|
+
{ className: `${CLD_SPBL_IMAGE} ${SHOPPABLE_WIDGET_RESPONSIVE_CLASS}` },
|
|
55
|
+
{ 'data-src': this.options_.item.url() }
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
el.appendChild(img);
|
|
59
|
+
|
|
60
|
+
if (this.getTitle()) {
|
|
61
|
+
const info = dom.createEl('div', { className: 'cld-spbl-item-info base-color-semi-bg text-color-text' });
|
|
62
|
+
const title = dom.createEl('span', { className: 'cld-spbl-item-title' }, {}, this.getTitle());
|
|
63
|
+
info.appendChild(title);
|
|
64
|
+
el.appendChild(info);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return el;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const addOnHover = (el, conf, cldConf) => {
|
|
72
|
+
el.setAttribute('data-hover-action', conf.action);
|
|
73
|
+
if (conf.action === SHOPPABLE_HOVER_ACTIONS.OVERLAY) {
|
|
74
|
+
const overlayText = dom.createEl('span', { className: 'cld-spbl-overlay-text base-color-text' }, {}, conf.args);
|
|
75
|
+
const overlay = dom.createEl('span', { className: 'cld-spbl-overlay text-color-semi-bg base-color-text' }, { title: conf.args }, overlayText);
|
|
76
|
+
el.appendChild(overlay);
|
|
77
|
+
} else {
|
|
78
|
+
|
|
79
|
+
const switchImgSource = new ImageSource(conf.args.publicId, {
|
|
80
|
+
cloudinaryConfig: cldConf,
|
|
81
|
+
transformation: conf.args.transformation
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const hoverImg = dom.createEl('img',
|
|
85
|
+
{ className: `${CLD_SPBL_IMAGE} cld-spbl-hover-img ${SHOPPABLE_WIDGET_RESPONSIVE_CLASS}` },
|
|
86
|
+
{ 'data-src': switchImgSource.url() }
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
el.appendChild(hoverImg);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const addOnClick = (el, conf) => {
|
|
94
|
+
el.setAttribute('data-click-action', conf.action);
|
|
95
|
+
el.setAttribute('data-pause', conf.pause);
|
|
96
|
+
if (conf.action === SHOPPABLE_CLICK_ACTIONS.SEEk) {
|
|
97
|
+
el.setAttribute('data-seek', conf.args.time);
|
|
98
|
+
} else if (conf.action === SHOPPABLE_CLICK_ACTIONS.GO_TO) {
|
|
99
|
+
el.setAttribute('data-goto-url', conf.args.url);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
videojs.registerComponent('shoppablePanelItem', ShoppablePanelItem);
|
|
104
|
+
|
|
105
|
+
export default ShoppablePanelItem;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
import { assign } from 'utils/assign';
|
|
3
|
+
import { throttle } from 'utils/throttle';
|
|
4
|
+
import { parseTime } from 'utils/time';
|
|
5
|
+
import 'assets/styles/components/playlist.scss';
|
|
6
|
+
import ShoppablePanelItem from './shoppable-panel-item';
|
|
7
|
+
import ImageSource from '../../../plugins/cloudinary/models/image-source';
|
|
8
|
+
import {
|
|
9
|
+
CLD_SPBL_PANEL_CLASS,
|
|
10
|
+
SHOPPABLE_CLICK_ACTIONS,
|
|
11
|
+
SHOPPABLE_PANEL_HIDDEN_CLASS,
|
|
12
|
+
SHOPPABLE_PANEL_VISIBLE_CLASS,
|
|
13
|
+
SHOPPABLE_PRODUCTS_OVERLAY_CLASS
|
|
14
|
+
} from '../shoppable-widget.const';
|
|
15
|
+
|
|
16
|
+
const Component = videojs.getComponent('Component');
|
|
17
|
+
|
|
18
|
+
class ShoppablePanel extends Component {
|
|
19
|
+
|
|
20
|
+
constructor(player, options = {}) {
|
|
21
|
+
super(player, options);
|
|
22
|
+
this.options = options;
|
|
23
|
+
|
|
24
|
+
const itemChangeHandler = () => {
|
|
25
|
+
this.render();
|
|
26
|
+
};
|
|
27
|
+
player.on('shoppableitemchanged', itemChangeHandler);
|
|
28
|
+
|
|
29
|
+
this.render();
|
|
30
|
+
|
|
31
|
+
this.dispose = () => {
|
|
32
|
+
super.dispose();
|
|
33
|
+
player.off('shoppableitemchanged', itemChangeHandler);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
createEl() {
|
|
38
|
+
const el = super.createEl();
|
|
39
|
+
[CLD_SPBL_PANEL_CLASS, 'base-color-bg'].map(cls => el.classList.add(cls));
|
|
40
|
+
return el;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
removeAll() {
|
|
44
|
+
const childrens = this.children();
|
|
45
|
+
for (let i = childrens.length - 1; i >= 0; --i) {
|
|
46
|
+
this.removeChild(childrens[i]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getItems() {
|
|
51
|
+
const cloudinaryConfig = this.player_.cloudinary.cloudinaryConfig();
|
|
52
|
+
return this.options.products.map(product => {
|
|
53
|
+
if (product.onHover && typeof product.onHover.args === 'object') {
|
|
54
|
+
product.onHover.args.transformation = assign({},
|
|
55
|
+
this.options.transformation,
|
|
56
|
+
product.onHover.args.transformation
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const conf = {
|
|
60
|
+
productId: product.productId,
|
|
61
|
+
productName: product.productName,
|
|
62
|
+
title: product.title,
|
|
63
|
+
onHover: product.onHover,
|
|
64
|
+
onClick: product.onClick,
|
|
65
|
+
startTime: product.startTime,
|
|
66
|
+
endTime: product.endTime
|
|
67
|
+
};
|
|
68
|
+
const imageSource = new ImageSource(product.publicId, {
|
|
69
|
+
cloudinaryConfig: cloudinaryConfig,
|
|
70
|
+
transformation: assign({}, this.options.transformation, product.transformation)
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
imageSrc: imageSource,
|
|
74
|
+
conf: conf
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
scrollToActiveItem() {
|
|
80
|
+
const activeItems = this.el_.getElementsByClassName('active');
|
|
81
|
+
if (activeItems.length > 0) {
|
|
82
|
+
const toScroll = activeItems[0].offsetTop - 12;
|
|
83
|
+
// Test for native scrollTo support (IE will fail)
|
|
84
|
+
if ('scrollBehavior' in document.documentElement.style) {
|
|
85
|
+
this.el_.scrollTo({
|
|
86
|
+
top: toScroll,
|
|
87
|
+
behavior: 'smooth'
|
|
88
|
+
});
|
|
89
|
+
} else {
|
|
90
|
+
this.el_.scrollTop = toScroll;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
render() {
|
|
96
|
+
this.removeAll();
|
|
97
|
+
|
|
98
|
+
const items = this.getItems();
|
|
99
|
+
|
|
100
|
+
const throttledScrollToActiveItem = throttle(() => this.scrollToActiveItem(), 1000);
|
|
101
|
+
|
|
102
|
+
items.forEach((item, index) => {
|
|
103
|
+
const shoppablePanelItem = new ShoppablePanelItem(this.player(), {
|
|
104
|
+
item: item.imageSrc,
|
|
105
|
+
conf: item.conf,
|
|
106
|
+
next: index === 1,
|
|
107
|
+
current: index === 0,
|
|
108
|
+
clickHandler: (e) => {
|
|
109
|
+
let target = e.currentTarget || e.target;
|
|
110
|
+
let evName = this.player_.ended() ? 'productClickPost' : 'productClick';
|
|
111
|
+
this.player_.trigger(evName, { productId: target.dataset.productId, productName: target.dataset.productName });
|
|
112
|
+
|
|
113
|
+
// Go to URL, or seek video (set currentTime)
|
|
114
|
+
if (target.dataset.clickAction === SHOPPABLE_CLICK_ACTIONS.GO_TO) {
|
|
115
|
+
window.open(target.dataset.gotoUrl, '_blank');
|
|
116
|
+
} else if (target.dataset.clickAction === SHOPPABLE_CLICK_ACTIONS.SEEk) {
|
|
117
|
+
const gotoSecs = parseTime(target.dataset.seek);
|
|
118
|
+
if (gotoSecs !== null) {
|
|
119
|
+
this.player_.addClass('vjs-has-started'); // Hide the poster image
|
|
120
|
+
if (this.player_.postModal) {
|
|
121
|
+
this.player_.postModal.close();
|
|
122
|
+
}
|
|
123
|
+
this.player_.currentTime(gotoSecs);
|
|
124
|
+
// Close products side-panel
|
|
125
|
+
this.player_.removeClass(SHOPPABLE_PANEL_VISIBLE_CLASS);
|
|
126
|
+
this.player_.addClass(SHOPPABLE_PANEL_HIDDEN_CLASS);
|
|
127
|
+
this.player_.addClass(SHOPPABLE_PRODUCTS_OVERLAY_CLASS);
|
|
128
|
+
// Wait for the time update and show the tooltips
|
|
129
|
+
this.player_.one('seeked', () => this.player_.trigger('showProductsOverlay'));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// pause - true (default), false, or number of seconds
|
|
134
|
+
if (target.dataset.pause !== 'false') {
|
|
135
|
+
this.player_.pause();
|
|
136
|
+
if (parseTime(target.dataset.pause)) {
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
this.player_.play();
|
|
139
|
+
}, parseTime(target.dataset.pause) * 1000);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
shoppablePanelItem.on('mouseover', e => {
|
|
146
|
+
let target = e.currentTarget || e.target;
|
|
147
|
+
let evName = this.player_.ended() ? 'productHoverPost' : 'productHover';
|
|
148
|
+
this.player_.trigger(evName, { productId: target.dataset.productId, productName: target.dataset.productName });
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (typeof item.conf.startTime !== 'undefined' && typeof item.conf.endTime !== 'undefined') {
|
|
152
|
+
this.player_.on('timeupdate', () => {
|
|
153
|
+
const time = this.player_.currentTime();
|
|
154
|
+
if (time >= item.conf.startTime && time < item.conf.endTime) {
|
|
155
|
+
shoppablePanelItem.el_.classList.add('active');
|
|
156
|
+
throttledScrollToActiveItem();
|
|
157
|
+
} else if (shoppablePanelItem.el_.classList.contains('active')) {
|
|
158
|
+
shoppablePanelItem.el_.classList.remove('active');
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.addChild(shoppablePanelItem);
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
videojs.registerComponent('shoppablePanel', ShoppablePanel);
|
|
171
|
+
|
|
172
|
+
export default ShoppablePanel;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
import ShoppablePanel from './panel/shoppable-panel.js';
|
|
3
|
+
import { CLD_SPBL_PANEL_CLASS } from './shoppable-widget.const';
|
|
4
|
+
const dom = videojs.dom || videojs;
|
|
5
|
+
|
|
6
|
+
class ShoppablePostWidget {
|
|
7
|
+
constructor(player, options = {}) {
|
|
8
|
+
this.options_ = { ...options, postPlay: true };
|
|
9
|
+
this.player_ = player;
|
|
10
|
+
this.render();
|
|
11
|
+
|
|
12
|
+
// Handle drag-to-scroll
|
|
13
|
+
this.handleDragToScroll();
|
|
14
|
+
|
|
15
|
+
this.dispose = () => {
|
|
16
|
+
this.layout_.dispose();
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
handleDragToScroll() {
|
|
21
|
+
const postModal = this.player_.postModal.el_;
|
|
22
|
+
const slider = postModal.querySelector(`.${CLD_SPBL_PANEL_CLASS}`);
|
|
23
|
+
|
|
24
|
+
let isDown = false;
|
|
25
|
+
let startX = 0;
|
|
26
|
+
let scrollLeft = 0;
|
|
27
|
+
|
|
28
|
+
slider.addEventListener('mousedown', (e) => {
|
|
29
|
+
isDown = true;
|
|
30
|
+
startX = e.pageX - slider.offsetLeft;
|
|
31
|
+
scrollLeft = slider.scrollLeft;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
document.addEventListener('mouseup', (e) => {
|
|
35
|
+
isDown = false;
|
|
36
|
+
setTimeout(() => {
|
|
37
|
+
slider.classList.remove('dragged');
|
|
38
|
+
}, 300);
|
|
39
|
+
|
|
40
|
+
const x = e.pageX - slider.offsetLeft;
|
|
41
|
+
const walk = x - startX;
|
|
42
|
+
if (Math.abs(walk) > 5) {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
document.addEventListener('mousemove', (e) => {
|
|
48
|
+
if (!isDown) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
const x = e.pageX - slider.offsetLeft;
|
|
53
|
+
const walk = (x - startX);
|
|
54
|
+
slider.scrollLeft = scrollLeft - walk;
|
|
55
|
+
if (Math.abs(walk) > 5 && !slider.classList.contains('dragged')) {
|
|
56
|
+
slider.classList.add('dragged');
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
render() {
|
|
62
|
+
|
|
63
|
+
this.player_.postModal = null;
|
|
64
|
+
|
|
65
|
+
const el = dom.createEl('div', { className: 'cld-spbl-post-play' });
|
|
66
|
+
const panel = new ShoppablePanel(this.player_, this.options_);
|
|
67
|
+
|
|
68
|
+
const title = dom.createEl('div', { className: 'cld-spbl-post-title base-color-text' }, {}, this.options_.bannerMsg || 'Shop the Video');
|
|
69
|
+
|
|
70
|
+
// Background - poster + blur effect
|
|
71
|
+
const bgSrc = this.player_.cloudinary.currentPoster();
|
|
72
|
+
bgSrc.transformation([
|
|
73
|
+
bgSrc.transformation().toOptions(),
|
|
74
|
+
{ effect: 'blur:3000' }
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
const panelBg = dom.createEl('div', {
|
|
78
|
+
className: 'cld-spbl-post-play-bg',
|
|
79
|
+
style: `background-image: url("${bgSrc.url()}")`
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const replayBtn = dom.createEl('button',
|
|
83
|
+
{
|
|
84
|
+
className: 'cld-spbl-replay-btn base-color-bg vjs-icon-replay',
|
|
85
|
+
onclick: () => {
|
|
86
|
+
this.player_.trigger('replay');
|
|
87
|
+
this.player_.postModal.close();
|
|
88
|
+
this.player_.play();
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{},
|
|
92
|
+
'Replay'
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
el.appendChild(panelBg);
|
|
96
|
+
el.appendChild(title);
|
|
97
|
+
el.appendChild(panel.el());
|
|
98
|
+
el.appendChild(replayBtn);
|
|
99
|
+
|
|
100
|
+
this.player_.postModal = this.player_.createModal(el, { name: 'postModal', uncloseable: true });
|
|
101
|
+
|
|
102
|
+
this.player_.addClass('cld-spbl-post-modal');
|
|
103
|
+
this.player_.postModal.on('beforemodalclose', () => {
|
|
104
|
+
this.player_.removeClass('cld-spbl-post-modal');
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default ShoppablePostWidget;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const SHOPPABLE_WIDGET_OPTIONS_DEFAULTS = {
|
|
2
|
+
location: 'right',
|
|
3
|
+
toggleIcon: '',
|
|
4
|
+
width: '20%',
|
|
5
|
+
startState: 'openOnPlay',
|
|
6
|
+
autoClose: 2,
|
|
7
|
+
transformation: {
|
|
8
|
+
quality: 'auto',
|
|
9
|
+
width: 'auto',
|
|
10
|
+
fetch_format: 'auto',
|
|
11
|
+
crop: 'scale'
|
|
12
|
+
},
|
|
13
|
+
products: [],
|
|
14
|
+
showPostPlayOverlay: false
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const SHOPPABLE_CLICK_ACTIONS = {
|
|
18
|
+
GO_TO: 'goto',
|
|
19
|
+
SEEk: 'seek'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const SHOPPABLE_HOVER_ACTIONS = {
|
|
23
|
+
OVERLAY: 'overlay'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const SHOPPABLE_WIDGET_RESPONSIVE_CLASS = 'cld-vp-responsive';
|
|
27
|
+
|
|
28
|
+
export const SHOPPABLE_PANEL_VISIBLE_CLASS = 'shoppable-panel-visible';
|
|
29
|
+
|
|
30
|
+
export const SHOPPABLE_PANEL_HIDDEN_CLASS = 'shoppable-panel-hidden';
|
|
31
|
+
|
|
32
|
+
export const SHOPPABLE_PRODUCTS_OVERLAY_CLASS = 'shoppable-products-overlay';
|
|
33
|
+
|
|
34
|
+
export const CLD_SPBL_PANEL_CLASS = 'cld-spbl-panel';
|
|
35
|
+
|
|
36
|
+
export const CLD_SPBL_TOGGLE_CLASS = 'cld-spbl-toggle';
|
|
37
|
+
|
|
38
|
+
export const CLD_SPBL_TOGGLE_ICON_CLASS = 'cld-spbl-toggle-icon';
|
|
39
|
+
|
|
40
|
+
export const CLD_SPBL_INNER_BAR = 'cld-spbl-bar-inner';
|
|
41
|
+
|
|
42
|
+
export const CLD_SPBL_TOGGLE_CUSTOM_ICON_CLASS = 'cld-spbl-toggle-custom-icon';
|
|
43
|
+
|
|
44
|
+
export const ICON_CART_CLASS = 'vjs-icon-cart';
|
|
45
|
+
|
|
46
|
+
export const CLOSE_ICON_CLASS = 'vjs-icon-close';
|
|
47
|
+
|
|
48
|
+
export const SHOPPABLE_ANIMATION_CLASS = 'animate';
|
|
49
|
+
|
|
50
|
+
export const CLD_SPBL_ITEM = 'cld-spbl-item';
|
|
51
|
+
|
|
52
|
+
export const CLD_SPBL_IMAGE = 'cld-spbl-img';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import videojs from 'video.js';
|
|
2
|
+
import ShoppableBarLayout from './layout/bar-layout';
|
|
3
|
+
import ShoppablePostWidget from './shoppable-post-widget';
|
|
4
|
+
import './shoppable-widget.scss';
|
|
5
|
+
import {
|
|
6
|
+
CLD_SPBL_INNER_BAR,
|
|
7
|
+
CLD_SPBL_PANEL_CLASS,
|
|
8
|
+
CLD_SPBL_TOGGLE_CLASS,
|
|
9
|
+
SHOPPABLE_PANEL_VISIBLE_CLASS,
|
|
10
|
+
SHOPPABLE_WIDGET_OPTIONS_DEFAULTS,
|
|
11
|
+
SHOPPABLE_WIDGET_RESPONSIVE_CLASS
|
|
12
|
+
} from './shoppable-widget.const';
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ShoppableWidget {
|
|
16
|
+
|
|
17
|
+
constructor(player, initOptions = {}) {
|
|
18
|
+
this.options_ = videojs.mergeOptions(SHOPPABLE_WIDGET_OPTIONS_DEFAULTS, initOptions);
|
|
19
|
+
this.player_ = player;
|
|
20
|
+
|
|
21
|
+
if (this.options_.showPostPlayOverlay) {
|
|
22
|
+
this.player_.on('ended', () => {
|
|
23
|
+
this.player_.addChild(new ShoppablePostWidget(this.player_, this.options_));
|
|
24
|
+
// Handle responsive images.
|
|
25
|
+
this.player_.player_.cloudinary.cloudinaryConfig().responsive({
|
|
26
|
+
responsive_class: SHOPPABLE_WIDGET_RESPONSIVE_CLASS
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
const width = this.options_.width;
|
|
33
|
+
|
|
34
|
+
this._injectCSS(`
|
|
35
|
+
.${CLD_SPBL_INNER_BAR} {
|
|
36
|
+
transform: translateX(${width});
|
|
37
|
+
}
|
|
38
|
+
.${SHOPPABLE_PANEL_VISIBLE_CLASS} .vjs-control-bar {
|
|
39
|
+
width: calc(100% - ${width});
|
|
40
|
+
}
|
|
41
|
+
.${CLD_SPBL_TOGGLE_CLASS} {
|
|
42
|
+
right: ${width};
|
|
43
|
+
}
|
|
44
|
+
.${CLD_SPBL_PANEL_CLASS}{
|
|
45
|
+
width: ${width};
|
|
46
|
+
}
|
|
47
|
+
`);
|
|
48
|
+
|
|
49
|
+
this._setListeners();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_setListeners() {
|
|
53
|
+
const resizeHandler = this._resizeHandler.bind(this);
|
|
54
|
+
|
|
55
|
+
this.player_.on('resize', resizeHandler);
|
|
56
|
+
window.addEventListener('resize', resizeHandler);
|
|
57
|
+
|
|
58
|
+
this.dispose = () => {
|
|
59
|
+
this.player_.off('resize', resizeHandler);
|
|
60
|
+
window.removeEventListener('resize', resizeHandler);
|
|
61
|
+
this.layout_.dispose();
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_injectCSS(css) {
|
|
66
|
+
const style = document.createElement('style');
|
|
67
|
+
style.innerHTML = css;
|
|
68
|
+
this.player_.el_.appendChild(style);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_resizeHandler() {
|
|
72
|
+
|
|
73
|
+
const shoppableBarBreakpoints = [
|
|
74
|
+
['sm', 0, 80],
|
|
75
|
+
['md', 81, 110],
|
|
76
|
+
['lg', 111, 170]
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const shoppableBarWidth = parseFloat(this.options_.width) / 100.0 * this.player_.el_.clientWidth;
|
|
80
|
+
let inRange = false;
|
|
81
|
+
if (shoppableBarWidth) {
|
|
82
|
+
for (const [name, min, max] of shoppableBarBreakpoints) {
|
|
83
|
+
if (shoppableBarWidth > min && shoppableBarWidth <= max) {
|
|
84
|
+
this.layout_.contentWrpEl_.setAttribute('size', name);
|
|
85
|
+
inRange = name;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!inRange) {
|
|
89
|
+
this.layout_.contentWrpEl_.removeAttribute('size');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
init() {
|
|
95
|
+
this.render();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
render() {
|
|
99
|
+
this.layout_ = new ShoppableBarLayout(this.player_, this.options_);
|
|
100
|
+
this.player_.on('loadeddata', () => {
|
|
101
|
+
// Handle responsive images.
|
|
102
|
+
this.player_.player_.cloudinary.cloudinaryConfig().responsive({
|
|
103
|
+
responsive_class: SHOPPABLE_WIDGET_RESPONSIVE_CLASS
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
export default ShoppableWidget;
|