Modifying Bootstrap 3's Collapse Animation with Animate.css - twitter-bootstrap-3

I managed to override the default "collapse in" animation for Bootstrap 3's collapse plugin but unable override the toggle back animation.
Basically I want it to fade in (which is doing now) and fade out on close which at the moment its defaulting to the default BS animation for that event.
Example jsfiddle
<div class="collapse animated fadeIn" id="collapseExample">
<div class="well">
...
</div>
</div>

After taking a look at the Bootstrap 3 documentation for "collapse" and This other question, I took over the events and managed to get it working.
I removed all animate.css classes from element.
jQuery to override the show and hide events generated by BS.
Create a class that would delay the transition on "hide".
Result jsfiddle
JS
$(function() {
var animateIn = 'animated fadeIn';
var animateOut = 'animated fadeOut collapsing-delay';
$('#collapseExample').on('show.bs.collapse', function () {
// do something…
$(this).addClass(animateIn).on('shown.bs.collapse',
function() {
$(this).removeClass(animateIn);
});
})
$('#collapseExample').on('hide.bs.collapse', function () {
// do something…
$(this).addClass(animateOut).on('hidden.bs.collapse',
function() {
$(this).removeClass(animateOut);
});
})
})
CSS
.collapsing-delay {
/* delay BS transition for animated fadeOut to show */
-webkit-transition-delay: 2s !important;
transition-delay: 2s !important;
}

Related

How can I listen to the scroll event in a sidebar [Bootstrap Vue]

I am using the Sidebar component from BootstrapVue to render a navigation for my application.
As an example, I have 30 menu items in my navigation, so the content within the sidebar scrolls vertically. I would like to bind to that scroll event to dynamiclly add/remove some classes.
I have tried to create a custom scroll directive:
Vue.directive('scroll', {
inserted: function(el, binding) {
console.log('el', el);
let f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
});
...then register that to the component within my vue file:
<b-sidebar
v-scroll="handleScroll"
title="Menu"
shadow="lg"
backdrop
#change="$emit('sidebar-change')"
...
handleScroll() {
console.log('handleScroll');
},
The directive is being picked up properly, but my handleScroll method is firing when the main body is scrolling, not the sidebar.
In my directive, I am logging to see what element it thinks it's working with:
<div tabindex="-1" class="b-sidebar-outer">...</div>
Since Bootstrap is dynamiclly creating the markup for the overlay, that's the parent element -- looking closer, I believe I need to attach my directive to this:
<div class="b-sidebar-body">...</div>
That is the <div> that looks to be scrolling. However, since it is generated at runtime, I don't know how to hook into that.
I have also tried using #native.scroll="myMethod" on the component...no luck there either.
How can I listen for the scroll event within my sidebar component? Thank you for any suggestions!
Your scroll listener fires on the main window because the directive attached the event listener to window, and not the element.
To listen to scroll events on the contents of b-sidebar, the listener should be on an element inside the default slot of b-sidebar (not the b-sidebar itself).
Put a wrapper div inside b-sidebar's default slot, and style it to enable scrolling:
<template>
<b-sidebar>
<div class="wrapper">
<!-- your actual contents here -->
</div>
</b-sidebar>
</template>
<style>
.wrapper {
overflow: auto;
height: 100%;
}
</style>
Add the custom v-scroll directive on the wrapper div:
<div class="wrapper" v-scroll="handleScroll">
Update the custom directive to add the binding value as the event listener on the given element's scroll event:
Vue.directive('scroll', (el, binding) => {
let f = (evt) => {
if (binding.value(evt, el)) {
el.removeEventListener('scroll', f)
}
}
el.addEventListener('scroll', f)
})
demo
You need to check whether the event's target is the sidebar and only execute your function if it is.

Resize button according to screen size

For a button, by default Bootstrap 4 allow you to set default button "size" between : xs, sm, md, lg, xl.
So, in my code, small screen first, i use sm size for screen <576px :
<button type="button" class="btn btn-success btn-sm"></button>
But for xl screen ≥1200px, need i to change size attribute or something else with Bootstrap to adjust button size ?
I don't really understand Bootstrap responsive behavior for button and 'size' attribute between small and large screen.
Thanks.
I don't think there's anything built out of the box for responsive buttons in bootstrap, you'd probably be better off extending the existing bootstrap button sizes in sass/media queries ie
.responsive-button {
#media (min-width: 576px) { #extend .btn-sm }
#media (min-width: 768px) { #extend .btn-md }
}
I haven't tested this so may need to research a bit further but hopefully this gets you on track :)
According to the Vue.js documentation, i had finally computed my CSS class dynamically according to window.onresizeevent call in mounted () function.
Example :
Here is my Bootstrap button :
<b-button :size="nsize" variant="outline-success" class="my-2 my-sm-0">
<font-awesome-icon icon="search"/>
</b-button>
Here is my function in App.vue file:
<script>
export default {
name: 'topnavbar',
data () {
return {
nsize: "sm",
mediaWidth: Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
}
},
mounted () {
if (window.addEventListener) {
window.addEventListener("resize", this.updateSize, false);
} else if (window.attachEvent) {
window.attachEvent("onresize", this.updateSize);
}
},
methods : {
updateSize: function (){
let sizeEl = "md";
let width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
if(width <= 576){
sizeEl = "sm";
}
this.nsize = sizeEl;
}
}
}
</script>
Sources:
Get the browser viewport dimensions with JavaScript
https://fr.vuejs.org/v2/guide/class-and-style.html

Can the <transition> element be used to animate individual page elements in a nuxtjs application?

Can someone tell me if the transition element can be used on page elements for animations in nuxt? I have seen the doc regarding page transitions, but I want to animate a number of different page elements. What I have so far does not appear to be working.
In a simple Header component, I have this:
<template>
<transition name="menu-popover">
<ul class="MenuPopover">
<li>Payments</li>
<li>Subscriptions</li>
<li>Connect</li>
</ul>
</transition>
And in the style tag of that component:
<style scoped>
.menu-popover-enter {
opacity: 0;
transform: rotateY(50deg);
}
.menu-popover-enter-to {
opacity: 1;
transform: rotateY(0deg);
}
.menu-popover-enter-active {
transition: opacity, transform 200ms ease-out;
}
Solution 1:
Look into the Nuxt Guide: Page Transition, it introduces how to implement the transition for each page (or specific pages Nuxt API: Page Transition) step by step very well.
Solution 2 (not recommend, but if really prefer to uses <nuxt /> inside one <transition> manually):
Steps:
put <nuxt> inside <transition>, like <transition name="test"><nuxt v-show="pageShow"/></transition>
add css class for transition effects,
css will be like:
.test-enter {
opacity: 0;
transform: rotateY(50deg);
}
.test-leave-to {
opacity: 0;
transform: rotateY(100deg);
}
.test-enter-active,.test-leave-active {
transition: all 2s ease-out;
}
add one handler for router navigator (or like button click event which will trigger route change).
The handler will be like below:
changePage: function (newUrl) {
this.pageShow = false //hide current page to trigger the transtion for `leave` current page
setTimeout(()=> {
this.pageShow = true //show new page, it will trigger the transition for `enter` new page
this.$router.replace(newUrl) //with new url
}, 2000) // delay 2s (after the transition of previous page finishes)
}

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>

say I have many divs and each div trigger an event when clicked

Dojo 1.7
say I have many divs and each div trigger an event when clicked. So when I cilck a div, dojo adds a class, say "clicked" to the div. But how can I set it so when I click another div, it removes the previous div class "clicked" and gives it to the div that I just clicked?
This is because if I clicked on one div it supposed to change its background and remove the background from the previously clicked div
Thanks!!!
You can put all these div in one container, for example
<div class='RadioDivContainer'>
<div> </div>
....
<div> </div>
<div>
Then do this in onclick event handler of divs:
dojo.query(".RadioDivContainer .clicked").forEach(function(node){
dojo.removeClass(node, "clicked");
});
dojo.addClass(evt.target, "clicked");
This is just show the idea how to implement it. You can change it to suit your case.
You can remove the clicked class from all the elements in the group before applying the clicked class to the newly-clicked element.
Using Dojo 1.7:
require([
'dojo/query',
'dojo/dom-class',
'dojo/on',
'dojo/dom',
'dojo/domReady!'
], function(query, dom_class, on, dom) {
var boxes = query('.box', dom.byId('#container')); // get elements inside #container
boxes.forEach(function(box) {
on(box, 'click', function() {
boxes.forEach(function(b) {
dom_class.remove(b, 'clicked');
});
dom_class.add(box, 'clicked');
});
});
});
Here's a fiddle.
You could also keep track of the last clicked element and remove the clicked class from that. You can see both examples in the fiddle.
You should enable hooks to your desired DOM elements with dojo.query, handle click events using dojo.on and assign/unassign classes with dojo/dom-class. Give the div elements a shared class to denote that they are part of this clickable unit, then listen for click events on all of them and assign classes as necessary. See this JSfiddle, using Dojo 1.7.4:
HTML
<div class="mutable"></div>
<div class="mutable"></div>
<div class="mutable"></div>
Javascript/Dojo
require(["dojo/query", "dojo/dom-class", "dojo/on", "dojo/domReady!"], function(query, domClass, on) {
on(query(".mutable"), "click", function(e) {
query(".mutable").forEach(function(node) {
domClass.remove(node, "clicked");
});
domClass.add(this, "clicked")
});
});
CSS
.mutable {
background-color:red;
}
.clicked {
background-color:green;
}
div {
border:2px solid black;
margin:5px;
}
This will also work with Dojo 1.8.x and 1.9.x.