How do you animate the opening and closing of accordion sections in Zurb Foundation 4? - accordion

How do you animate the opening and closing of accordion sections in Zurb Foundation 4?
I've done extensive searching on Zurb Foundation's Google group and couldn't find any answers there either.

I wrote a fairly simple jQuery plugin to get this working. The plugin has default options, while also allowing overrides via the data-options attribute.
Tested on Foundation 5.
Here's the plugin:
(function($) {
$.fn.accordionAnimated = function() {
var
$accordion = this,
$items = $accordion.find('> dd'),
$targets = $items.find('.content'),
options = {
active_class : 'active', // class for items when active
multi_expand: false, // whether mutliple items can expand
speed : 500, // speed of animation
toggleable: true // setting to false only closes accordion panels when another is opened
}
;
$.extend(options, Foundation.utils.data_options($accordion));
$items.each(function(i) {
$(this).find('a:eq(0)').on('click.accordion', function() {
if(!options.toggleable && $items.eq(0).hasClass(options.active_class)) {
return;
}
$targets.eq(i)
.stop(true, true)
.slideToggle(options.speed);
if(!options.multi_expand) {
$targets.not(':eq('+i+')')
.stop(true, true)
.slideUp(options.speed);
}
});
});
};
}(jQuery));
and the plugin is simply invoked via
$('.accordion').accordionAnimated();
Hope this helps someone.

Assuming you're using Foundation's HTML classes:
.top-bar-section {
-webkit-transition: 0.2s all ease-in;
-moz-transition: 0.2s all ease-in;
-o-transition: 0.2s all ease-in;
transition: 0.2s all ease-in;
}

Related

Position the dialog at the center of the screen in Fiori

I have a SAPUI5 Fiori application.
I use theme sap_fiori_3 as the base theme.
I customized this theme and only attached a background image to the theme.
The interesting part is when I activate this customized theme (that only has an extra background image in comparison to original sap_fiori_3 theme), the dialog are not centered in my app anymore.
The dialog are made with sap.m.dialog class.
I wrote a small snippet of code to center the dialog like following:
onAfterDialogOpen: function(oEvent){
var oDialog = oEvent.getSource(),
$Dialog = oDialog.$(),
oPosition = $Dialog.position(),
iTop = oPosition.top,
iLeft = oPosition.left,
iDialogWidth = $Dialog.width(),
iDialogHeight = $Dialog.height(),
iScreenWidth = sap.ui.Device.resize.width,
iScreenHight = sap.ui.Device.resize.height,
iNewTop = Math.floor((iScreenHight-iDialogHeight)/2),
iNewLeft = Math.floor((iScreenWidth-iDialogWidth)/2);
if(Math.abs(iNewLeft-iLeft) > 10 & Math.abs(iNewTop-iTop) > 10){
$Dialog.offset({top: iNewTop, left: iNewLeft});
}
},
But it is not a good solution. Why? Because it makes a motion on my screen like following:
Now the question is, how can I center the dialog without Java Script and by settings or some other tricks that when the dialog is opened, it be already centered.
Please note that using onBeforeOpen event is not possible as I need the size and position of the dialog!
I finally found out what is the source of the problem. It seems the Theme Designer of SAP is buggy and some part of the theme code does not transfer to the exported file.
When I use the theme designer to customize the theme it not only made the mentioned error, but also some other strange behavior appear in the deployed applications in the fiori launchpad which use the customized theme. However, we don't have those errors in the development time in the WEB IDE.
Therefore as I only needed to customize the following items:
background image
logo
favicon
I tried to use the standard theme like sap_fiori_3 and work around for setting these properties.
So for the first 2 issues I used the CSS hack:
div.sapUShellFullHeight {
background-image: url(../images/myBackgroundImage.svg);
background-repeat: no-repeat;
background-size: contain;
background-position: right;
}
a#shell-header-logo > img#shell-header-icon {
content:url(../images/logo.svg);
}
And for the favicon I used the promise solution. Please notice in the fiori launchpad each time that you switch between the applications fiori will reset the favicon, so I used the JavaScript promise to set it.
// Set the favicon dynamically to get read of blinking
function waitForElementAppear(selector) {
return new Promise(function(resolve, reject) {
var element = document.querySelector(selector);
if(element) {
resolve(element);
return;
}
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var nodes = Array.from(mutation.addedNodes);
for(var node of nodes) {
if(node.matches && node.matches(selector)) {
observer.disconnect();
resolve(node);
return;
}
};
});
});
observer.observe(document.documentElement, { childList: true, subtree: true });
});
}
//
function waitForElementRemoved(selector) {
return new Promise((resolve) => {
var element = document.querySelector(selector);
if(!element) {
resolve();
return;
}
var observer = new MutationObserver((mutations, observer) => {
for (const mutation of mutations) {
for (const removedNode of mutation.removedNodes) {
if (removedNode === element) {
observer.disconnect();
resolve();
}
}
}
});
observer.observe(element.parentElement, { childList: true });
});
}
//
function changeFavIcon(selector) {
waitForElementAppear(selector).then(function(element) {
element.setAttribute("href", "icon/favicon.ico");
waitForElementRemoved(selector).then(function() {
changeFavIcon(selector);
});
});
};
changeFavIcon("link[rel='shortcut icon']");
It recursively checks when the favicon is injected then it will set its href and as soon as it is removed, this function will observe the next injection!
As I know somebody may says why not used sapui5 its original solution for setting the favicon, like this:
jQuery.sap.setIcons({
'phone': '/images/cimt-logo.png',
'phone#2': '/images/cimt-logo.png',
'tablet': '/images/cimt-logo.png',
'tablet#2': '/images/cimt-logo.png',
'favicon': '/icon/favicon.ico',
'precomposed': true
});
I must say it was not working in my case!

Leaflet Draw icons do not appear in production mode on Vue

I have a Vue application using Leaflet as a map library. On the map, I've added a toolbar using Leaflet Draw and a button with Leaflet EasyButton. I give an image in order to illustrate below:
Development
The problem has started to appear when I created a build version of my Vue application to save on my server. The Leaflet Draw icons do not appear anymore. Just the Leaflet EasyButton icon is showing.
Production
My code is as follows:
this.llmap = L.map('map-id', {...})
let vectorLayerDraw = L.featureGroup([])
this.llmap.addControl(new L.Control.Draw({
position: 'topright',
draw: {
...
rectangle: {
shapeOptions: {
color: '#000000',
opacity: 0.2,
fillOpacity: 0.1
}
}
},
edit: {
featureGroup: vectorLayerDraw,
poly: {
allowIntersection: false
}
}
}))
Would anyone know what can be happening?
Thank you in advance.
I was looking for the question on the internet and I've found the following solution:
.leaflet-draw-toolbar a {
background-image: url('../assets/spritesheet.png');
background-repeat: no-repeat;
color: transparent !important;
}
Where I add the image manually on my static folder and I overwrite the background-image.
Sources: 1 and 2
Thank you so much.

Make default Ionic alerts larger

I'm trying to make the default Ionic Alerts larger. I'm developing an app that needs to have easy touch points and the default alerts are too small for what I'm needing.
I've tried enlarging the font as well as expanding the width of the alerts but nothing seems to actually make the alerts larger.
Any easy/best ways to do this?
AlertController supports custom classes which could be placed in your component's scss file and there you can do necessary alterations.
For example in your component's ts file you can have this method that creates alert with reference to custom class "scaledAlert":
delete() {
let confirm = this.alertCtrl.create({
title: "Are You Sure?",
cssClass: "scaledAlert",
message: "this will remove image from your image gallery",
buttons: [
{
text: "Cancel",
handler: () => {
console.log("Canceled delete");
}
},
{
text: "Confirm",
handler: () => {
console.log("deleting...");
this.deleteImageFromGallery(this.image)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
this.viewCtrl.dismiss();
}
}
]
});
confirm.present();
}
Now in the scss file you add class to style as you need to scale the controller, such class goes after your page or component:
home-page {
.item {
min-height: 2rem; /* <- this can be whatever you need */
}
ion-label {
margin: 0px 0px 0px 0;
}
.item-content {
padding-top: 0px;
padding-bottom: 0px;
margin-top: -12px;
margin-bottom: -12px;
height: 50px;
}
}
.scaledAlert {
transform: scale(1.5);
}
Here I used just naive "scale" function which may require you to add some cross browser compatible versions of it. But you should achieve what you want with it (it worked in my app without issues).
Alternatively you can override default styles using saas variables: https://ionicframework.com/docs/api/components/alert/AlertController/#sass-variables
You will have to alter them in theme\variables.scss" which is located in your project's folder
See more here: https://ionicframework.com/docs/theming/overriding-ionic-variables/
And third option is indeed to check elements' style via devtool and attempt to override those classes. But I don't like that way, feels a bit more hacky.
Some of the styles for alert are not getting updated if written in component SCSS file. The styles need to be written in the global scss file.

Detect scrollHeight change with MutationObserver?

How can I detect when scrollHeight changes on a DOM element using MutationObserver? It's not an attribute and it isn't data either.
Background: I need to detect when a scrollbar appears on my content element, the overflow-y of which is set to auto. I figured that the instant the scrollbar appears the value of scrollHeight jumps from 0 to, say, 500, so the idea was to set up a MutationObserver to detect a change in this property.
What I've got so far:
HTML
<div class="body" #body>
CSS
.body {
overflow-y: auto;
}
TypeScript
export class MyWatchedContent implements AfterViewInit, OnDestroy {
#ViewChild('body', { read: ElementRef })
private body: ElementRef;
private observer: MutationObserver;
public ngAfterViewInit() {
this.observer = new MutationObserver(this.observerChanges);
this.observer.observe(this.body.nativeElement, {
attributes: true,
});
}
public ngOnDestroy() {
this.observer.disconnect();
}
private observerChanges(records: MutationRecord[], observer: MutationObserver) {
console.log('##### MUTATION');
records.forEach((_record) => {
console.log(_record);
});
}
}
If I, for example, change the background color in the developer window I can see the observer firing
MUTATION
my-content-watcher.component.ts?d0f4:233 MutationRecord {type: "attributes", target: div.body, addedNodes: NodeList(0), removedNodes: NodeList(0), previousSibling: null…}
If, however, I change the window size to make the scrollbar appear there's no mutation detected. Is this doable with MutationObserver at all and if so, how?
Here's the answer, for anyone still looking for the solution:
As of today, it's not possible to directly monitor scrollHeight changes of an element.
The MutationObserver detects changes in the DOM tree, which could indicate a scrollHeight change, but that's a wild guess.
The ResizeObserver detects changes in the outer height of an element, but not the scrollHeight (i.e. "inner" height).
There is no ScrollHeight-Observer (yet).
BUT the solution is very close:
The Solution
The ResizeObserver detects changes in the outer height of an element...
There's no point in observing the scroll-container because its outer height does not change. The element that changes their out height is any CHILD node of the container!
Once the height of a child node changes, it means, that the scrollHeight of the parent container changed.
Vanilla JS version
const container = document.querySelector('.scrollable-container');
const observer = new ResizeObserver(function() {
console.log('New scrollHeight', container.scrollHeight);
});
// This is the critical part: We observe the size of all children!
for (var i = 0; i < container.children.length; i++) {
observer.observe(container.children[i]);
})
jQuery version
const container = $('.scrollable-container');
const observer = new ResizeObserver(function() {
console.log('New scrollHeight', container[0].scrollHeight);
});
container.children().each(function(index, child) {
observer.observe(child);
});
Further steps
When children are added dynamically, you could add a MutationObserver to add new children to the ResizeObserver once they were added.
You can emulate this behavior by adding an internal wrapping element on the contenteditable element (eg a span) and then add the ResizeObserver listener on the internal element. The internal span has to be display:block otherwise it wont trigger the ResizeObserver.
HTML
<div contenteditable id="input"><span id="content">Some content</span></div>
CSS
#input {
max-height: 100px;
overflow: scroll;
white-space: pre-wrap;
}
#content {
display: block;
white-space: pre-wrap;
}
JS
const content = document.getElementById("content");
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
console.warn(entry);
}
});
observer.observe(content);

Disable back fade popup

Is it possible to disable the popup backfade?
I tried this:
My popup controller:
var popupInvalid = $ionicPopup.alert({
templateUrl: 'templates/popup-template-invalid.html',
cssClass: 'success-popup',
scope: $scope
})
Sass:
.success-popup{
.backdrop {
opacity: 0 !important;
}
}
But I did not succeed
Thanks
Unfortunately the backdrop is a sibling of .popup-container, which then contains your popup. So the only option you have is to globally modify the .backdrop class, e.g.:
.backdrop
{
background-color: transparent;
}
Check this example: http://play.ionic.io/app/8f14ab72d922
Unfortunately this influences all other popups in your application as well.