LESS mixin: How to loop through passed in arguments - less

I usually write SASS, but for a particular project I have to use LESS.
How do I achieve something like the below using less? Using sass the mixin can be called like #include align(hcenter top) to position an element horizontally in the middle and to the top.
#mixin align($styles) {
position: absolute;
content: '';
display: block;
#each $style in $styles {
#if ($style == center) {
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
#if ($style == hcenter) {
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
#if ($style == vcenter) {
margin-top: auto;
margin-bottom: auto;
top: 0;
bottom: 0;
}
#if ($style == top) {
top: 0;
}
#if ($style == bottom) {
bottom: 0;
}
#if ($style == right) {
right: 0;
}
#if ($style == left) {
left: 0;
}
}
}

See Mixin Arguments, List Functions and Loops.
With a thing like "for" the snippet can be converted to something like:
#import "loops/for";
#usage {
.align(hcenter, top, bottom, etc);
}
.align(#styles...) {
position: absolute;
content: '';
display: block;
.for(#styles); .-each(#style) {
& when (#style = center) {
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
& when (#style = hcenter) {
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
& when (#style = vcenter) {
margin-top: auto;
margin-bottom: auto;
top: 0;
bottom: 0;
}
& when (#style = top) {
top: 0;
}
& when (#style = bottom) {
bottom: 0;
}
& when (#style = right) {
right: 0;
}
& when (#style = left) {
left: 0;
}
}
}
---
Actually above code can be optimized to more compact:
.align(#styles...) {
position: absolute;
content: '';
display: block;
.center(#pos) {
margin-#{pos}: auto;
#{pos}: 0;
}
.for(#styles);
.-each(center) {.-each(hcenter); .-each(vcenter)}
.-each(hcenter) {.center(left); .center(right)}
.-each(vcenter) {.center(top); .center(bottom)}
.-each(#style) when (default()) {#{style}: 0}
}
Though this way it may look more confusing for one not too familiar with Less.

I'm not sure about your each loop. For instance (center, top;) will set top: 0; twice?
But you can try:
.align(#styles){
.setproperties(#iterator:1) when (#iterator <= length(#styles)) {
#style: extract(#styles,#iterator);
& when (#style = center) {
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
& when (#style = hcenter)
{
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
// add more & when 's here
.setproperties((#iterator + 1));
}
position: absolute;
content: '';
display: block;
.setproperties();
}
The above can be called with:
selector1 {
.align(center;);
}
selector2 {
.align(center hcenter;);
}

Related

What does "$root: &" mean in sass?

I'm trying to understand sass files of Splide ( https://splidejs.com/ ).
In many files there are codes like this one
.splide {
$root: &;
&--ttb {
> #{$root}__pagination {
display: flex;
right: 1em;
bottom: 50%;
left: auto;
flex-direction: column;
transform: translate(0, 50%);
#{$root}__pagination__page {
width: $indicator-height;
height: $indicator-width;
}
}
}
}
What the $root: &; means?
In your snippet, $root is just the name of the variable.
You could give it another name, like $foo.
$root: & is equivalent here to $root: .splide as & in sass refers to the parent selector.
It means that:
.splide {
$root: &;
&--ttb {
> #{$root}__pagination {
display: flex;
right: 1em;
bottom: 50%;
left: auto;
flex-direction: column;
transform: translate(0, 50%);
#{$root}__pagination__page {
width: $indicator-height;
height: $indicator-width;
}
}
}
}
Is equivalent to:
.splide {
&--ttb {
> .splide__pagination {
display: flex;
right: 1em;
bottom: 50%;
left: auto;
flex-direction: column;
transform: translate(0, 50%);
.splide__pagination__page {
width: $indicator-height;
height: $indicator-width;
}
}
}
}
And will compile to:
.splide--ttb > .splide__pagination {}
.splide--ttb > .splide__pagination .splide__pagination__page {}

How to Remove Numbers in Steps in PrimeNG?

I am using PrimeNG Steps. How to remove the numbers in steps?
I tried using the Default CSS Property.
component has no option for this ,but you can use css to hide the innerHtml by after pseudo-element
style.scss (global style)
p-steps{
.ui-steps-number {
overflow: hidden
}
.ui-steps-number::after {
content: '';
background: currentColor;
width: 100%;
height: 100%;
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
.ui-steps .ui-steps-item.ui-state-highlight .ui-steps-number {
color: #007ad9 !important;
}
.ui-steps .ui-steps-item .ui-steps-number {
color: #ccc !important;
}
}
demo 🚀
the style above will change the style for all p-steps components but you can use custom styleClass like this
template
<p-steps styleClass="dot-theme" [model]="items"
[(activeIndex)]="activeIndex" [readonly]="false">
</p-steps>
style.scss
.dot-theme {
.ui-steps-number {
overflow: hidden
}
.ui-steps-number::after {
content: '';
background: currentColor ;
width: 100%;
height: 100%;
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
.ui-state-highlight .ui-steps-number {
color: #007ad9 !important;
}
.ui-steps-number {
color: #ccc !important;
}
}
demo 🌟
You can simply hide the text setting it's colour to transparent:
.p-steps .p-steps-item .p-menuitem-link .p-steps-number {
color: transparent;
}

I would like to delay something after it's been clicked

I'm creating a multiple choice question program and I have it so that once the correct answer is chosen a new question is generated.
Although I want it to go to the next question automatically, I want it to delay for about 0.5 seconds so the user can see that their answer is correct.
I chose to remove the class and replace it with another class so that the background changes colour. Once the new question comes up I want all the colours to return to normal, so I once again remove the new class and replace it with the old class.
If I don't advance to the new question automatically, the colours come up just the way I like them, but if I create it so that it moves on automatically, I am unable to keep the display the same.
After searching through the forums I read that setTimeout should work, but I haven't had much success. I have also tried doing animations so that it takes time, but that didn't work for me either. The animations worked fine, but it still went on to the new set of questions.
I'll include the whole program as it might be better but the section I'm working on is under the function check().
I've been trying to figure out how to delay something for a long time but have been completely unsuccessful. Oh, please be kind to me, I have very little experience. I have only learned how to do javascript by doing the khan academy course. Thanks!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Project: listening to sounds </title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- ***************** CSS styles ***************** -->
<style>
body {
font-family: comic sans ms, sans-serif;
background-image: url("background.jpg");
background-color: rgb(216, 252, 252);
}
form {
font-size: 1.2em;
}
#text {
background-color: wheat;
width: 150px;
height: 25px;
color: blue;
font-size: 1em;
}
.SoundBite {
float: left;
clear: none;
position: absolute;
top: 130px;
left: 100px;
padding: 5px;
background: darkblue;
color: white;
height: 120px;
width: 200px;
border-radius: 50px;
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 5em;
}
.SoundBite:hover {
background-color: darkgreen;
cursor: pointer;
}
.Score {
float: right;
clear: none;
position: absolute;
top: 50px;
left: 140px;
padding: 5px;
background: darkblue;
border-color: pink;
border: 5px;
opacity: 0.8;
color: white;
height: 45px;
width: 120px;
border-radius: 50px;
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 2em;
pointer-events: none;
}
.Answer {
position: absolute;
color: white;
height: 45px;
width: 120px;
padding: 5px;
border-radius: 25px;
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 2em;
background-color: darkblue;
}
.AnswerCorrect {
position: absolute;
color: white;
height: 45px;
width: 120px;
padding: 5px;
border-radius: 25px;
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 2em;
background-color: green;
}
.Answer:hover {
background-color: #e44404;
cursor: pointer;
}
.AnswerWrong {
position: absolute;
color: white;
height: 45px;
width: 120px;
padding: 5px;
border-radius: 25px;
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 2em;
background-color: red;
}
#Answer1 {
top: 20px;
left: 400px;
}
#Answer2 {
top: 85px;
left: 400px;
}
#Answer3 {
top: 150px;
left: 400px;
}
#Answer4 {
top: 220px;
left: 400px;
}
#Answer5 {
top: 290px;
left: 400px;
}
</style>
</head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<body>
<audio id="audio" src="audio/rug.mp3" autostart="false" ></audio>
<audio id = "win" src="audio/win.mp3" autostart = "true"></audio>
<audio id = "lose" src = "audio/lose.mp3" autstart = "true"></audio>
<a onclick="playSound();"><div span class="SoundBite"><i class="fa fa-file-sound-o" id="audio" src="audio/rug.mp3" autostart="false" style="font-size:64px;color:skyblue"></i></div></a>
<a onclick ="checkAnswer = 1; check();"><div class = "Answer" id="Answer1">1</div>
<a onclick ="checkAnswer = 2; check();"><div class = "Answer" id="Answer2">2</div>
<a onclick ="checkAnswer = 3; check();"><div class = "Answer" id="Answer3">3</div>
<a onclick ="checkAnswer = 4; check();"><div class = "Answer" id="Answer4">4</div>
<a onclick ="checkAnswer = 5; check();"><div class = "Answer" id="Answer5">5</div>
<div class = "Score">Score</div>
<!-- <a onclick ="next();"><div id = "Next">Start</div> -->
<!-- ********************************* Javascript programming follows ********************************* -->
<script>
$(function() {
});
// declare the variables to be used ... do I need global variables? Maybe I should think about these...
var word, ext, directory, wordPosition, decoyWordPosition, answerPosition, decoyAnswerPosition, answer, checkAnswer, correct, incorrect, tries;
directory = "audio/";
ext = ".mp3";
correct = 0;
incorrect = 0;
tries = 0;
// list of words that are spoken
word = ["dam", "dog", "dug", "cat", "cot", "cut", "ran", "rot", "rug"];
wordPosition = Math.floor(Math.random()*word.length); // returns a random array wordPosition
/***************************************************************************
** Functions:
**
**************************************************************************/
// function to display word
function displayWord() {
//$(".SoundBite").text(word[wordPosition]);
//$("#audio").attr("src", directory+word[wordPosition]+ext);
}
// function to display the answer in one of the positions that are assigned
function displayAnswer(answerNumber, wordNumber) {
$("#Answer"+answerNumber).text(word[wordNumber]);
$("#audio").attr("src", directory+word[wordPosition]+ext);
}
// function to play the sound
function playSound() {
var sound = document.getElementById("audio");
sound.play();
}
// function to play a winning sound
function win() {
var sound = document.getElementById("win");
sound.play();
}
// function to play a losing sound
function lose() {
var sound = document.getElementById("lose");
sound.play();
}
function timer() {
new Date().toLocaleTimeString();
}
function check() {
if (answer == checkAnswer) {
//$("#Answer"+checkAnswer).animate({height: "45px", opacity: '0'})
//.animate({height: "45px", opacity: '1.0'});
$("#Answer"+checkAnswer).animate({height: "45px", opacity: '0'})
.animate({height: "45px", opacity: '1.0'})
.removeClass("Answer").addClass("AnswerCorrect");
win();
correct++;
tries++;
refresh();
next();
// need a delay function -- can't get it to work.
} else {
$("#Answer"+checkAnswer).removeClass("Answer").addClass("AnswerWrong"); //css({'background-color': 'red'});
lose();
incorrect++;
tries++;
}
// write in the score
$(".Score").text(Math.round(correct/tries*100)+"%");
}
// making a function to populate the answers
function populateAnswers() {
for (var i = 0; i < 6; i++) {
if (answerPosition < 6) {
if (decoyWordPosition == wordPosition) {
answer=answerPosition
}
displayAnswer(answerPosition, decoyWordPosition);
answerPosition++;
decoyWordPosition++;
if (decoyWordPosition >= word.length) { // want to make sure that the words are within the array
decoyWordPosition = 1 // reset to the beginning to 'wrap' the array.
}
} else {
answerPosition = 1;
}
}
}
// using a random generator to place the answer in a random spot 1 through 4
function randomGenerator() {
answerPosition = Math.floor(Math.random()*4)+1;
}
// returns a random array wordPosition
function randomWord() {
wordPosition = Math.floor(Math.random()*word.length);
}
function refresh() {
for (var i = 1; i <= 5; i++) {
$("#Answer"+i).removeClass("AnswerWrong").addClass("Answer");
$("#Answer"+i).removeClass("AnswerCorrect").addClass("Answer");
}
}
/***************************************************************************
* program as a function *
**************************************************************************/
function next() {
$("#Next").text("Continue");
randomWord();
randomGenerator();
// make the decoy answers randomly
if (wordPosition == 0 || wordPosition == 1) {
// In case the array is at the beginning: make the decoy start at the same spot as the wordPosition
decoyWordPosition = wordPosition;
} else {
// start the decoy word after the word
decoyWordPosition = wordPosition -2;
}
populateAnswers();
}
next();
</script>
</body>
</html>
Just for other people who are trying to find the solution to the setTimeout feature.
I was using it like this:
setTimeout(myFunction(), 2000);
However, it won't work with the brackets after the function. You need to omit those brackets:
setTimeout(myFunction, 2000);

Use computed value in element using less.js

Have the following bit of code:
generate-margins(4);
.generate-margins(#n, #i: 1) when (#i =< #n) {
.marginleft#{i} {
margin-left: (5px * #i);
}
.marginright(5*#{i}) {
margin-right: (5px * #i);
}
.generate-margins(#n, (#i + 1));
}
Which gives me:
.marginleft1 {
margin-left: 5px;
}
.marginright(5*1) {
margin-right: 5px;
}
.marginleft2 {
margin-left: 10px;
}
.marginright(5*2) {
margin-right: 10px;
}
.marginleft3 {
margin-left: 15px;
}
.marginright(5*3) {
margin-right: 15px;
}
.marginleft4 {
margin-left: 20px;
}
.marginright(5*4) {
margin-right: 20px;
}
What I wanted was:
.marginright5 {... }
.marginright10 {... }
...
How can use computed value in element name? I tried using all string functions with no luck.
Did some more testing and came up with this:
.generate-margins(#n, #i: 1) when (#i =< #n) {
#l : #i*5;
.marginleft#{l} {
margin-left: (5px * #i);
}
.marginright#{l} {
margin-right: (5px * #i);
}
.generate-margins(#n, (#i + 1));
}
Would still like to know if there is another way. Cheers.

Simple Gallery Slider

I'm trying to create a simple slider using divs and javascript. I set up a div with six images and an arrow that movies the containder holding the images 528px (the width of each image) every time it's clicked. When I reach the begining or end of the gallery, I want the respective arrow button to fade out so that the user won't keep pressing next/prev.
Any help is appreciated.
JAVASCRIPT
$("#btn-gallery-next").click(function(){
$("div#gallery li").not(this).removeClass('clicked');
$("div#gallery-slide").animate({left:"-=528px"});
if($("div#gallery-slide").position().left < -3168)
{
$("#btn-gallery-next").fadeOut();
}
else {
$("#btn-gallery-next").fadeIn();
}
});
$("#btn-gallery-prev").click(function(){
$("div#gallery li").not(this).removeClass('clicked');
$("div#gallery-slide").animate({left:"+=528px"});
if($("div#gallery-slide").position().left > 0)
{
$("#btn-gallery-prev").fadeOut();
}
else {
$("#btn-gallery-prev").fadeIn();
}
});
HTML
<div id="gallery-slide">
<img class="gallery-img" src="_/img/gallery/img1.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img2.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img3.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img4.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img5.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img6.jpg" alt="" />
</div>
Try flex slider from woothemes, it have all ur needs.
Why not use a slider library like Owl Slider? It comes with lots of options and configurations. It is super simple to integrate into any project.
Example #1 www.midwestgathering.com/#galleries
Example #2 www.owlgraphic.com/owlcarousel/demos/images.html
Another option is jcarousel. The basic slider is shown with an example that makes the left next button inactive until the user slides to the right, then once the user gets to the end of the gallery the right next button becomes inactive:
JS
(function($) {
$(function() {
$('.jcarousel').jcarousel();
$('.jcarousel-control-prev')
.on('jcarouselcontrol:active', function() {
$(this).removeClass('inactive');
})
.on('jcarouselcontrol:inactive', function() {
$(this).addClass('inactive');
})
.jcarouselControl({
target: '-=1'
});
$('.jcarousel-control-next')
.on('jcarouselcontrol:active', function() {
$(this).removeClass('inactive');
})
.on('jcarouselcontrol:inactive', function() {
$(this).addClass('inactive');
})
.jcarouselControl({
target: '+=1'
});
$('.jcarousel-pagination')
.on('jcarouselpagination:active', 'a', function() {
$(this).addClass('active');
})
.on('jcarouselpagination:inactive', 'a', function() {
$(this).removeClass('active');
})
.jcarouselPagination();
});
})(jQuery);
CSS
.jcarousel-wrapper {
margin: 20px auto;
position: relative;
border: 10px solid #fff;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 0 2px #999;
-moz-box-shadow: 0 0 2px #999;
box-shadow: 0 0 2px #999;
}
.jcarousel-wrapper .photo-credits {
position: absolute;
right: 15px;
bottom: 0;
font-size: 13px;
color: #fff;
text-shadow: 0 0 1px rgba(0, 0, 0, 0.85);
opacity: .66;
}
.jcarousel-wrapper .photo-credits a {
color: #fff;
}
/** Carousel **/
.jcarousel {
position: relative;
overflow: hidden;
width: 600px;
height: 400px;
}
.jcarousel ul {
width: 20000em;
position: relative;
list-style: none;
margin: 0;
padding: 0;
}
.jcarousel li {
float: left;
}
/** Carousel Controls **/
.jcarousel-control-prev,
.jcarousel-control-next {
position: absolute;
top: 200px;
width: 30px;
height: 30px;
text-align: center;
background: #4E443C;
color: #fff;
text-decoration: none;
text-shadow: 0 0 1px #000;
font: 24px/27px Arial, sans-serif;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
-webkit-box-shadow: 0 0 2px #999;
-moz-box-shadow: 0 0 2px #999;
box-shadow: 0 0 2px #999;
}
.jcarousel-control-prev {
left: -50px;
}
.jcarousel-control-next {
right: -50px;
}
.jcarousel-control-prev:hover span,
.jcarousel-control-next:hover span {
display: block;
}
.jcarousel-control-prev.inactive,
.jcarousel-control-next.inactive {
opacity: .5;
cursor: default;
}
/** Carousel Pagination **/
.jcarousel-pagination {
position: absolute;
bottom: 0;
left: 15px;
}
.jcarousel-pagination a {
text-decoration: none;
display: inline-block;
font-size: 11px;
line-height: 14px;
min-width: 14px;
background: #fff;
color: #4E443C;
border-radius: 14px;
padding: 3px;
text-align: center;
margin-right: 2px;
opacity: .75;
}
.jcarousel-pagination a.active {
background: #4E443C;
color: #fff;
opacity: 1;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.75);
}
You can find documentation for jcarousel at www.sorgalla.com/jcarousel/docs/.
see demo - http://codepen.io/vsync/pen/waKju?editors=011
javascript
/**
* Slider - loops over images
* SEP 2014
* By - Yair Even-Or
*/
var Slider = function(elm, prev, next){
var that = this;
this.locked = false;
this.slider = elm;
this.children = this.slider.children;
this.itemWidth = this.children[0].clientWidth;
this.preloadImages();
next && next.addEventListener('click', function(){ that.move('next') });
prev && prev.addEventListener('click', function(){ that.move('prev') });
}
Slider.prototype = {
move : function(dir){
var that = this,
itemToMove;
if( this.locked ){
this.locked.removeAttribute('style');
this.slider.appendChild(this.locked);
clearTimeout(this.timer);
moveToEnd();
}
// do nothing if there are no items
if( this.children.length < 2 )
return false;
itemToMove = this.children[0];
this.locked = itemToMove;
if( dir == 'next' )
itemToMove.style.marginLeft = -this.itemWidth + 'px';
else{
itemToMove = this.children[this.children.length-1];
itemToMove.style.marginLeft = -this.itemWidth + 'px';
this.slider.insertBefore(itemToMove, this.children[0]);
setTimeout(function(){
itemToMove.removeAttribute('style');
},50);
this.preloadImages();
this.locked = false;
}
// move the child to the end of the items' list
if( dir == 'next' )
this.timer = setTimeout(moveToEnd, 420);
function moveToEnd(el){
itemToMove = el || itemToMove;
if( !itemToMove ) return;
itemToMove.removeAttribute('style');
that.slider.appendChild(itemToMove);
that.locked = false;
that.preloadImages();
}
},
preloadImages : function(){
this.lazyload(this.children[1].getElementsByTagName('img')[0] );
this.lazyload(this.children[this.children.length-1].getElementsByTagName('img')[0] );
},
// lazy load image
lazyload : function(img){
var lazy = img.getAttribute('data-src');
if( lazy ){
img.src = lazy;
img.removeAttribute('data-src');
}
}
}
// HOW TO USE /////////////////
var sliderElm = document.querySelector('.content'),
next = document.querySelector('.next'),
prev = document.querySelector('.prev'),
slider = new Slider(sliderElm, prev, next);
HTML (JADE syntax)
.slider
a.arrow.next
a.arrow.prev
ul.content
li
img(src='image1.jpg')
li
img(src='image2.jpg')
li
img(src='image3.jpg')
li
img(src='image4.jpg')