How to make gulp-clean-css preserve whitespace before !important? - gulp

When optimizing the code gulp-clean-css removes the vital whitespace from between css values and the closing !important word, eg. width: 600px !important becomes width: 600px!important
By the way, the level 1 semicolonAfterLastProperty: true setting does not work either!
I have read the documentation here - https://github.com/jakubpawlowicz/clean-css#formatting-options - and tried to use level1 transform: function () {} but it does not work.
.pipe(cleanCSS({
format : 'beautify',
level: {
1: {
transform: function (propertyName, propertyValue, selector ) {
if (propertyValue.indexOf('!important') > -1) {
return propertyValue.replace('!important', ' !important');
}
},
semicolonAfterLastProperty: true
},
2 : {
removeDuplicateRules : true
}
}
}))
The only solution so far that worked was to surround critical parts of the code by
/* clean-css ignore:start */ .... /* clean-css ignore: end */, but I am looking for some nicer way.

Well, it looks that the gulp-replace plugin is at help:
From gulpfile.js:
const replace = require('gulp-replace');
... CUT ...
and:
.pipe(replace('!important', ' !important'))

Related

Why class returned in eventClassNames of V5 is not applied?

With fullcalendar v5.7.2 in Alpinejs 2 app I want to set different color for cells depending
on some property and reading here https://fullcalendar.io/docs/classname-input
I catch event :
dayMaxEvents: true,
views: {
dayGridMonth: {
editable: false
}
},
events: function (info, successCallback, failureCallback) { //get data from db for selected dates
self.select_year = parseInt(moment(info.start).format('YYYY'))
self.select_month = parseInt(moment(info.start).format('MM'))
var dataArray = {
'_token': '{{ $csrf_token }}',
'start': moment(info.start).format('YYYY-MM-DD'),
'end': moment(info.end).format('YYYY-MM-DD'),
'ad_categories': self.searchSelectedCategoryIds,
'users': self.searchSelectedUserIds,
'status': self.searchStatus,
'text': self.searchText
}
window.axios.post('/admin/get_ad_events', dataArray).then((response) => {
successCallback(response.data.events);
}).catch((error) => {
console.error(error)
failureCallback(error)
popupAlert('Calendar', 'Run time error : ' + getErrorMessage(error), 'error')
});
}, // events: function(info, successCallback, failureCallback) { //get data from db for selected dates
eventClassNames: function(arg) {
// return 'fullcalendar_nearest_days'; // if to uncomment this line it does not work anyway
if (arg.event.extendedProps.is_past) {
return [ 'fullcalendar_nearest_days' ]
} else {
return [ 'normal' ]
}
I check and see that fullcalendar_nearest_days is returned, but it is's properties are not applied
and checking events code I do not see “fullcalendar_nearest_days” in events styling...
Which way is correct ?
MODIFIED:
fullcalendar_nearest_days is defined as :
.fullcalendar_nearest_days {
background-color: red !important;
color: yellow !important;
font-weight: bold;
}
and looking at generated code I found that fullcalendar_nearest_days is the latest class in "a" tag class definition:
<div class="fc-daygrid-event-harness fc-daygrid-event-harness-abs"
style="visibility: hidden; top: 0px; left: 0px; right: 0px;"><a
class="fc-daygrid-event fc-daygrid-dot-event fc-event fc-event-draggable fc-event-resizable fc-event-start fc-event-end fc-event-past fullcalendar_nearest_days"
data-id="undefined"><span class="flex flex-nowrap"><
Can it be that properties of fullcalendar_nearest_days are not applied as they are overwritten by fc-daygrid-event fc-daygrid-dot-event fc-event fc-event-draggable fc-event-resizable fc-event-start fc-event-end fc-event-past ?
Can I remove all/part of these classes in "a" tag class definition for some dates?
Thanks!
I made a demo using your CSS - https://codepen.io/ADyson82/pen/zYwYxRp . There doesn't seem to be a problem for timed events, the class is applied to the correct events and the colours change as you'd expect.
However on all-day events the yellow colour is not applied. If you use the element inspector in your browser you can see what CSS rules are applied to each element and what is overriding them. You can see that the title is inside another div within the main element, which has fc-event-main class on it, and that class has a rule which overrides the color property again.
Fortunately we can solve this easily by adjusting the CSS rule to deal with that situation specifically:
.fullcalendar_nearest_days, .fullcalendar_nearest_days .fc-event-main {
background-color: red !important;
color: yellow !important;
font-weight: bold;
}
Working demo: https://codepen.io/ADyson82/pen/OJmJPEP

Angular: Changing font-size using css variables is applying but not reflecting in browser for certain fields

I am using CSS variables for a feature where the user has an option to change the font-size to small, medium or large. So for most of the fields, it's working as expected. But for certain fields, the value is applied but not reflected
:host-context(.mediumFont) {
--fontSize: 11px;
}
:host-context(.largeFont) {
--fontSize: 12px;
}
:host-context(.smallFont) {
--fontSize: 10px;
}
refClassArray: RefClassInterface[] = [
{ class: 'font-small', refClass: 'smallFont' },
{ class: 'font-medium', refClass: 'mediumFont' },
{ class: 'font-large', refClass: 'largeFont' },
];
defaultFontSize = 'mediumFont';
changeFontSize(selector: string) {
this.defaultFontSize = selector;
let docBody = document.body;
console.log(document.getElementById(selector));
docBody.classList.add(selector);
this.refClassArray.forEach((refClass: RefClassInterface) => {
if (selector !== refClass.refClass) {
docBody.classList.remove(refClass.refClass);
document.querySelector('#' + refClass.refClass).setAttribute('style', 'font-weight: normal;' + 'pointer-events: auto;');
} else {
document.querySelector('#' + refClass.refClass).setAttribute('style', 'font-weight:' + 'bold;' + 'pointer-events: none;');
}
});
this.ieStyles.iEfont(selector);
}
Above is the logic I am using.
The first pic is from the element which is working fine. When I hover over the --font-size, 11px is reflected. The second one is the one where it's not working as expected and when I hover over the --font-size nothing is appearing. And both these elements are inside <body>
You should not be modifying your html code via direct access. This can open leave your application vulnerable to XSS Attacks for instance.
Instead, the Angular Team recomends the use of the Renderer2.
Taking your code and modifying it to use it, would lead to the following:
refClassArray: RefClassInterface[] = [
{ class: 'font-small', refClass: 'smallFont' },
{ class: 'font-medium', refClass: 'mediumFont' },
{ class: 'font-large', refClass: 'largeFont' },
];
defaultFontSize = 'mediumFont';
changeFontSize(selector: string, indexOfClassToAdd: number) {
this.defaultFontSize = selector;
const el: Element = document.getElementById(selector));
// Iterate each class in the list to remove it.
this.refClassArray.forEach((refClass: RefClassInterface) => {
// Remove the class from the specific element only if its present.
if (el.classList.contains(refClass.refClass) {
this.renderer2.removeClass(el, refClass.refClass);
};
});
this.renderer2.addClass(el, refClassArray[indexOfClassToAdd].refClass);
};
This would imply that you are aware of what is the class to be applied (and it being present in the style.scss or and the appropriate scss file).
Kind regards.
Out of curiosity, why are you doing it this way rather than simply using a class with the desired text size?
Either way, it looks like your value is not being applied because your selector is not specific enough.
To correct for this, you could make an artificially specific selector with something like this:
html > body * { // rules }
Why not use ngClass?
Define three classes
.font-small{
fontSize: 10px
}
.font-medium{
fontSize: 11px
}
.font-large{
fontSize: 12px
}
Bind something to the user select, like userChoice: SizeEnum or something
Then, on your data element, use ngClass to bind
ngClass = "{
'font-small': userChoice === sizeEnum.small,
'font-medium': userChoice === sizeEnum.medium,
'font-large': userChoice === sizeEnum.large
}"
The issue was resolved by moving
:host-context(.mediumFont) {
--fontSize: 11px;
}
:host-context(.largeFont) {
--fontSize: 12px;
}
:host-context(.smallFont) {
--fontSize: 10px;
}
from app.component.scss to styles.scss. Because the pop-ups are not a part of app.compontnet.html they render outside it.

Using CSS Variables on Stripe Elements

I am using Stripe Elements for a credit card checkout. The issue is, that I am not able (or I simply don't know how) to use my own CSS variables on this Stripe Element.
I need to use CSS variables for the sake of changing colors when the user changes the theme. Here is my current implementation:
Variable definitions (I'm using SASS)
.theme1
--color-1: red
--color-2: pink
// ...
.theme2
--color-1: blue
--color-2: lilec
// ...
.theme3
--color-1: orange
--color-2: yellow
// ...
// ...
The CSS variables are defined under the scope of a class, that is put to the body depending which theme is currently selected.
HTML (I am using Angular 6)
<div #stripe></div>
Typescript
#ViewChild('stripe') el: ElementRef;
card: any;
cardHandler = this.onChange.bind(this);
async onSubmit() { /* ... */ }
setupStripe(): void {
this.card = stripeElements.create('card', {
iconStyle: 'solid',
style: {
base: {
iconColor: 'var(--some-var)',
// using css variables here does not work
// ...
},
}
});
this.card.mount(this.el.nativeElement);
this.card.addEventListener('change', this.cardHandler);
}
destroyStripe(): void {
this.card.removeEventListener('change', this.cardHandler);
this.card.destroy();
}
ngAfterViewInit() {
this.setupStripe();
}
ngOnDestroy() {
this.destroyStripe();
}
onChange({ error }) { /* ... */ }
Styles (I am using SASS)
.StripeElement
background-color: var(--dy-bg-1)
// I don't have access to font colors etc here
color: var(--dy-txt-1) !important
// !important also does not work
P.S.: It's important for me, that the variables will change at runtime (which is the reason I'm using CSS variables.
The Stripe documentation says
Elements creates UI components for you that are hosted by Stripe
i.e. their input fields are in a different document, so don't have access to your custom CSS variables.
A 'good enough' solution might be to read the CSS Custom Property values in your setupStripe method, and pass the values over as plain strings:
// Note: document.body is just an example:
const styles = getComputedStyle(document.body);
this.card = stripeElements.create("card", {
iconStyle: "solid",
style: {
base: {
iconColor: styles.getPropertyValue("--some-var")
// ...etc
}
}
});

PhantomJS: Nested tables insert whitespace between rows

I have following HTML code:
https://gist.github.com/enlilcz/4c8baf50f35838ed5bb2
And phantomJs inserts this whitespace:
Almost no styles is on page, and I believe this problem is not about styles.
Problem is in nested tables - there is table in table.
When is removed parent table - removed lines 23-26 and 230-233 in HTML
and whitespace just dissapear.
PhantomJs settings is:
{
outputFormat: "pdf",
html: "myHTML",
version: 2,
phantomParams: {
paperSize: {
format: "A4",
margin: "0px"
}
}
}
And when I substitute paperSize to
viewportSize: {
'width': 2750, // or any other dimensions
'height': 3850
}
it also starts to work, but I need to use paperSize...
Does anyone knows where is the problem?

MooTools Effect Chaining

I'd like to be able to do something like this:
var fx = new Fx.Tween($('element'), {
duration: 500,
property: 'opacity',
transition: Fx.Transitions.Quart.easeOut,
link: 'chain'
});
fx.start(0, 1)
.chain(function() {
alert('foo');
})
.start(1, 0)
.chain(function() {
alert('bar');
});
Which then fades in #element, and then runs a function. However, I can't get it to run the second start after the first chain(), which means that #element isn't fading back in.
Thanks for your help
It turns out that something very similar to the above code can work except you need to use callChain() in order for the next "link" to fire.. This is what I'm using now:
var effect = new Fx.Tween($('element'));
effect.start('opacity', 1)
.chain(function() { /* Do stuff */ this.callChain();)
.chain(function() { /* Do stuff */ this.callChain();)
.chain(function() { /* Do stuff */ this.callChain();)
.chain(function() { /* Do stuff */ this.callChain();)
.chain(function() { /* Do stuff */);
And so on.
This is because chain returns and instance of the Chain class, rather than an instance of Fx.Tween. I'm a little annoyed that I need to use callChain() but it's better than having loads of nested functions.