GLightbox and HTML5 videos - how can I set a poster image? - html5-video

I am using GLightbox in a project I am working on. I have a hyperlink that has a URL to a self-hosted MP4 video. The video is opened in a GLightbox. I have poster images already setup for my videos, but I can't figure out where to set the poster image in the Glightbox setup. Here is my html link that launches the video in the lightbox.
<a href="<?= $video_url; ?>" class="standard-lightbox">
Here is the javascript configuration I have in my site.js file:
let standardLightboxSlideHTML = `<div class="gslide">
<div class="gslide-inner-content">
<div class="ginner-container">
<div class="gslide-media">
</div>
<div class="gslide-description">
<div class="gdesc-inner">
<h4 class="gslide-title"></h4>
<div class="gslide-desc"></div>
</div>
</div>
</div>
</div>
</div>`;
var standardLightbox = GLightbox({
selector: '.standard-lightbox',
width: '1280px',
height: '720px',
skin: 'modern',
closeOnOutsideClick: true,
slideHTML: standardLightboxSlideHTML,
type:'video',
autoplayVideos: false,
plyr: {
config: {
ratio: '16:9', // or '4:3'
muted: false,
hideControls: false,
autoplay: false,
autopause: true,
volume: 0.5,
controls: ['play-large', 'play','progress','volume','mute','fullscreen']
}
}
});
I have tried adding a data-poster value to the hyperlink. That didn't work. That is where I would like to set it and then I want to GLightbox to use it. Any ideas how to make that work?
I want to tag this post as "glightbox", but I don't have enough rep.

I was able to resolve my problem this way.
In wordpress I setup two new fields, one for the url to the video and another for the poster image.
I changed my code to output the url and poster urls in the hyperlink that is clicked.
In my Glightbox setup, I just grab those values and add it dynamically with javascript to the video tag. I also add a counter to the hyperlink so I can append the count value to create an ID selector for the video.
standardLightbox.on('slide_after_load', (data) => {
const { slideIndex, slideNode, slideConfig, player, trigger } = data;
var btnClicked = document.getElementById(trigger.id);
var posterimage = btnClicked.getAttribute('data-html5videoposter');
var videoid = btnClicked.getAttribute('data-videoid');
// use the index
var getVideoTag = document.getElementById(videoid);
getVideoTag.setAttribute('poster', posterimage);
});

Related

Vue-Leaflet map doesn't render completely [duplicate]

Update: I have put my answer. Please see it.
Original Question:
Can you tell me why leaflet map doesn't show on the full map area?
.html
<ion-content padding>
<div style="height: 100%;width:100%" leaflet [leafletOptions]="options" *ngIf="options" [leafletCenter]="center">
</div>
</ion-content>
.ts
init(): void {
this.options = {
layers: [
tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { maxZoom: 18, attribution: "..." })
],
zoom: 10,
center: this.center = latLng(Number(this.activatedRoute.snapshot.paramMap.get("latitude")), Number(this.activatedRoute.snapshot.paramMap.get("longitude"))),
attributionControl: false,
};
}
UI
Please see the image. It seems a problem with transform. Default it was 0,0,0. I have changed it manually on the browser like so. So how can I set it to the map?
I had the same issue in an ionic 4 project. Like suggested in comment with link I needed to use map.invalidateSize() when I rendered the map, as well as when adding/removing markers or any other action for that matter. This didn't help completely. I also had to manually trigger change detection after that. Here's a sample from our code:
this.map.setView([this.myLocation.latitude, this.myLocation.longitude], 13);
this.map.invalidateSize();
this.ref.detectChanges();
where ref refers to ChangeDetectorRef.
Also make sure that you have the the leaflet css imported in your angular.json file:
"styles": [
// ....
"./node_modules/leaflet/dist/leaflet.css"
]
In my opinion the leaflet is filled 100% in its parents space, can you use the browsers inspect tool to see what is the parents width and height. You can also try using
position: absolute; left: 0;
to ignore parents width
Try removing the padding and changing height to 100vh
Try this:
<ion-content>
<div style="height: 100vh; width:100%" leaflet [leafletOptions]="options" *ngIf="options" [leafletCenter]="center">
</div>
</ion-content>
If you want to set the transform do it like so:
<ion-content padding>
<div style="height: 100%; width:100%; transform: translate3D(250px, 200px, 100px)" leaflet [leafletOptions]="options" *ngIf="options" [leafletCenter]="center">
</div>
</ion-content>
Here I'm using this with Ionic 4 app. I have tried many solutions given by different devs. But none of them worked for me. The problem here is the life cycle event which I have used earlier. So now I use ionViewDidEnter() and no issues.
ionViewDidEnter() {
this.center = latLng(Number(this.activatedRoute.snapshot.paramMap.get("latitude")), Number(this.activatedRoute.snapshot.paramMap.get("longitude")));
this.options = {
layers: [
tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { maxZoom: 18, attribution: "..." })
],
zoom: 17,
center: this.center,
attributionControl: false,
};
this.layers.push(this.mapService.getMarker(this.center, "assets/icon/map/placeholder.png"));
}
I had the same problem, even with the import of leaflet.css and the "invalidateSize()" trick.
It was because I wrote in "myComponent.page.html":
<ion-content>
<div id="map" style="height:400px; width: 100%;"></div>
</ion-content>
It seems Ionic4 css conflicts with leaflet.
You need to get the <div> outside of <ion-content>.
Correct is just :
<div id="map" style="height:400px; width: 100%;"></div>
Hope this help someone
map.invalidateSize() runs after window resize event.
So after height change, just write the code :
window.dispatchEvent(new Event('resize'));
this.map.invalidateSize();
It works like a charm in my case.
Dont' forget to replace map with your map variable.
My it helps someone

IntersectionObserver not registering on iOS, but works on Android, in Nuxt

What I have
I have made use of IntersectionObserver on my feed page. It behaves like TikTok. Scroll up or down to see the next video. On enter the video plays. On exit, it stops playing.
The Problem
It works on Android and Windows perfectly. On iOS, not so much. The videos are not autoplaying as expected. A bit strange though, is if I click the video (which calls play() on that video), and then scroll it out of view, the video does stop. When I scroll it back into view, it auto plays again. So I know that IntersectionObserver is being recognized, just not triggered initially.
The Code
==================================
The Feed Page, where the Observer is being instantiated:
data() {
return {
observer: null,
}
};
mounted() {
let config = { threshold: 0.1 };
if (process.client) {
if (/iPhone|iPad/i.test(navigator.userAgent)) {
config.root = null;
}
}
this.observer = new IntersectionObserver(function (entries) {
entries.forEach(({ target, isIntersecting }) => {
if (isIntersecting) {
target.play();
} else {
target.pause();
target.currentTime = 0;
}
});
}, config);
beforeDestroy() {
this.observer.disconnect();
},
HTML
<div
v-for="(post, index) in posts"
:key="index"
>
<MobileFeedItem :post="post" :observer="observer" />
</div>
=================================
The MobileFeedItem component
props: ["post", "observer"],
mounted() {
this.$nextTick(() => {
if (this.observer !== null && this.checkMediaTypeIsVideo(this.post)) {
this.observer.observe(
document.getElementById(
`video_${this.getContentId(this.post)}_mobile`
)
);
}
});
HTML
<video
:id="`video_${getContentId(post)}_mobile`"
:data-poster="getThumbnail(post)"
preload="none"
disablePictureInPicture
crossorigin
loop
playsinline
v-lazy-load
class="w-full h-full my-4"
>
<source :data-src="getMedia(post)" type="video/mp4" />
</video>
My Thoughts...
The observer is being instantiated and recognized, just not triggered. So is there a way that I can force the browser to wake up and become aware of the observer without having to click on each of the video elements first?
I found the answer. It wasn't anything wrong with the IntersectionObserver, but because my video was not muted.
"By default, autoplay executes only if the video doesn’t contain an audio track, or if the video element includes the muted attribute. Video playback pauses if the element gains an audio track, becomes unmuted without user interaction, or if the video is no longer onscreen"
source - https://developer.apple.com/documentation/webkit/delivering_video_content_for_safari
It also appears that we don't need intersection observer at all for Safari, as it does this for us. Huh.

Aframe Add Preloader to image loading in sky

I have a scene where I am changing the src for sky using buttons I created "outside the scene". Currently everything works fine but I would like to show a preloader while waiting for the next image to load.
Here you can see my scene: http://scriptstrainer.com/vr_training/
Below I have provided some of my code:
<a-scene>
<a-sky src="images/0-1.jpg" id="img-src">
</a-scene>
<div>
<img src="images/t1.png">
</div>
<div>
<img src="images/t2.png">
</div>
<div>
<img src="images/t3.png">
</div>
<script>
var sky = document.querySelector('#img-src');
var button1 = document.querySelector('#button1');
var button2 = document.querySelector('#button2');
var button3 = document.querySelector('#button3');
button1.addEventListener('click', function() {
sky.setAttribute('src', 'images/0-1.jpg');
});
button2.addEventListener('click', function() {
sky.setAttribute('src', 'images/2.JPG');
});
button3.addEventListener('click', function() {
sky.setAttribute('src', 'images/3.JPG');
});
</script>
Thanks for your assistance...
https://aframe.io/docs/0.4.0/components/material.html#events_materialtextureloaded
There's an event materialtextureloaded you can use to detect when the texture has loaded onto the mesh. In between the time you request to set the texture and the time the texture is set, you can display a loading graphic.
button1.addEventListener('click', function() {
sky.setAttribute('src', 'images/0-1.jpg');
// Display something in the meantime.
sky.addEventListener('materialtextureloaded', function () {
// Small timeout just in case?
setTimeout(function () { // Remove the placeholder. }, 100);
});
});
The loading graphic can be like a spinning object in the scene, a fade-in black mask around the camera (as used in https://github.com/aframevr/360-image-gallery-boilerplate). It depends on what you want it to be.
I had the same scenario where I wanted to add a preloader and only when the image is displayed, to remove the preloader.
I tried using events 'load' and 'loaded' but didn't work as I found out images are not displayed once they finish loading.
Eventually I got help from the AFrame GitHub page and that's how I did it:
<a-assets>
<img id='img-src' src='image.jpg'/>
</a-assets>
<a-sky src='#img-src' id='sky-id'></a-sky>
<script type='text/javascript'>
var skyEl = document.querySelector('#sky-id');
function loaded()
{
var preloader = document.querySelector('#preloader');
preloader.style.display = "none";
}
skyEl.addEventListener('materialtextureloaded', loaded);
</script>

Magnific Popup - gallery images not displaying

I'm trying to use Magnific Popup in collaboration with elevateZoom, I have it working to a point where I have bound a click handler to the zoom container, which in this case is the .product-image-gallery div.
If I pass a single image src, e.g. $j('.product-image-gallery .gallery-image').attr('src'); as the src: argument then I get a popup with an image, but as soon as I pass a more general selector such as the .gallery-image on its own, i get a 'The image could not be loaded' message.
The aim is to have the popup let me cycle through all the avaliable product images.
HTML:
<div class="product-image-gallery">
<img id="image-main" class="gallery-image visible" src="example1.jpg" alt="Title" title="Title" />
<img id="image-0" class="gallery-image" src="example1.jpg" data-zoom-image="example1.jpg" />
<img id="image-1" class="gallery-image" src="example2.jpg" data-zoom-image="example2.jpg" />
<img id="image-2" class="gallery-image" src="example3.jpg" data-zoom-image="example3.jpg" />
</div>
JS ($j because jQuery is in noConflict mode):
$j.magnificPopup.open({
items: {
src: '.gallery-image',
type: 'image',
gallery: {
enabled: true
}
}
});
I ended up building an object then passing that to magnific-popup, my solution:
$j('.product-image-gallery').bind('click', function(){
galleryObj = [];
$j('.product-image-gallery .gallery-image').not('#image-main').each(function() {
var src = $j(this).data('zoom-image'),
type = 'image'; // it's always an image :)
image = {};
image ["src"] = src;
image ["type"] = type;
galleryObj.push(image);
});
// open the popup
$j.magnificPopup.open({
items: galleryObj,
gallery: {
enabled: true
},
});
});

How to make a dojo dijit tab blink or flash when an event occurs and it is not the active tab?

I have a dojo dijit tab container and I want the tabs to flash a few times when an event occurs and it is not the selected tab. For example, when I receive a chat message I want the "Chat tab" to flash a few times as a visual notification that a chat has been received. I'm having a hard time finding the right control (the tab) to modify. Here is the code:
The HTML:
<div data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region:'center',splitter: true">
<div id="tabChat" title="Chat" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="iconClass:'i-chat', design: 'sidebar'">
<div id="pnlChatLog" style="background-color:#FFF; padding:0px;" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center', splitter:true">
<div id="divChatLog" style="width:100%; height:100%; overflow-y:scroll; overflow-x:hidden;">
</div>
</div>
<div id="pnlChatMessage" style="background-color:#FFF; padding:0px; overflow:hidden;" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'bottom', splitter:false">
<input id="txtChatMessage" style="width:100%; margin:0px; border:0px;" data-dojo-type="dijit.form.ValidationTextBox" data-dojo-props="intermediateChanges:false,placeholder:'Enter Message'" />
</div>
</div>
<div id="tabQuestions" title="Questions" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="iconClass:'i-help', design: 'sidebar'">
<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="region:'center', splitter:false, gutters:false">
<div style="background-color:#FFF; padding:0px; border-top:0px;" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center', splitter:true">
<div id="gridQuestions"></div>
</div>
</div>
</div>
The javaScript:
//Chat message Event
chat.on("message", function(e) {
//Message code is here...
//TODO: Make the tab flash if it is not the current tab
});
Note: The messaging code (not shown here) works. I just need to know what javaScript will replace the TODO section so the tab blinks/flashes for a few seconds at this point.
To get to the tab button you have to use the tab element's "controlButton" then modify the domNode. Here is an example:
//A method for the blinking using setInterval. The top line shows
//how to get the actual tab that you want to modify. Then add and remove the
//Hover classes for a nice flashing/blinking effect.
function blinkTab(tabId, count, interval) {
var tabbutton = dijit.byId(tabId).controlButton.domNode;
var interval = setInterval(function(){
if(count % 2 == 0) {
tabbutton .className += " dijitTabHover";
tabbutton .className += " dijitHover";
}
else {
//Not sure this is the best way to remove a class but I couldn't find
//a "clean" way to do it with dojo.
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitTabHover(?!\S)/ , '');
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitHover(?!\S)/ , '');
}
if(count == 0) {
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitTabHover(?!\S)/ , '');
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitHover(?!\S)/ , '');
clearInterval(interval);
}
count--;
}, interval);
}
//Now make the calls where desired
//Chat message Event
chat.on("message", function(e) {
//Message code is here...
blinkTab("tabChat", 10, 500);
});
//Question Event
questions.on("message", function(e) {
//Question code is here...
blinkTab("tabQuestions", 10, 500);
});
You might just want to change the "class" of the tab title span (or is it a div? don't remember). The easy way is to use firebug, check the element used for the tab title, identify it in the node hierarchy, then put an id on your tab like tabMsg or something, then you justy ned to dijit.byId to get the right tab, and then go to the title node and addClass/removeClass every seconds or 0.5s to make it "blink".
You might want to add a "blinking" property to your tab, so that while this is true you switch classes, and when you click on the tab you set it to false and disable the blinking.