Dynamic class names in LESS - class

I have the following bit of LESS code working
#iterations: 940;
#iterations: 940;
#col:2.0833333333333333333333333333333%;
// helper class, will never show up in resulting css
// will be called as long the index is above 0
.loopingClass (#index) when (#index > -20) {
// create the actual css selector, example will result in
// .myclass_30, .myclass_28, .... , .myclass_1
(~".gs#{index}") {
// your resulting css
width: (#index/20+1)*#col;
}
// next iteration
.loopingClass(#index - 60);
}
// end the loop when index is 0
.loopingClass (-20) {}
// "call" the loopingClass the first time with highest value
.loopingClass (#iterations);
It outputs our grid system as so:
.gs940 {
width: 100%;
}
.gs880 {
width: 93.75%;
}
.gs820 {
width: 87.5%;
}
.gs760 {
width: 81.25%;
}
.gs700 {
width: 75%;
}
etc etc etc
Now what I want to do is some math to the class names to produce the following classes
.gs220-700
.gs280-640
.gs340-580
.gs400-520
.gs460-460
.gs520-400
.gs580-340
.gs640-280
.gs700-220
etc etc etc
basically this would be
.(#index) - (920px minus #index)
But I have no idea if this is possible.

This whole question was very helpful to me. I just wanted to post the solution to my problem as the way to do it has changed since LESS v 1.4. LESS Changelog
Rather than using the ~ sign, you just write out the portion of the name that you want along with the normal # and variable name with {} surrounding it. So: #class#{variable}.
For example, my solution using the same sort of loop became such:
/*Total number of passport inserts*/
#numInserts: 5;
/*Total width of the passport foldouts*/
#passportWidth: 300px;
/*Change in passport insert width per iteration*/
#passportWidthDiff: (#passportWidth / #numInserts);
/*"Array" of colors to select from to apply to the id*/
#passportColors:
blue orange green red yellow
purple white teal violet indigo;
/*The faux loop the doesn't end up in the final css
#index is the counter
#numInserts is the total number of loops*/
.loopingClass (#index) when (#index <= #numInserts){
/*This is the created ID with the index appended to it
You can also do this with classes such as if
we had had ".insert#{index}"*/
#insert#{index}{
/*Here are our properties that get adjusted with the index*/
width: (#passportWidth - (#passportWidthDiff * (#numInserts - #index)));
height: 50px;
background-color: extract(#passportColors, #index);
z-index: (#numInserts - #index);
}
/*Here we increment our loop*/
.loopingClass(#index + 1);
}
/*This calls the loop and starts it, I started from 1
since I didn't want to lead a className starting from 0,
But there is no real reason not to. Just remember to
Change your conditional from "<=" to "<"*/
.loopingClass(1);
And produces the following:
#insert1 {
width: 60px;
height: 50px;
background-color: #0000ff;
z-index: 4;
}
#insert2 {
width: 120px;
height: 50px;
background-color: #ffa500;
z-index: 3;
}
#insert3 {
width: 180px;
height: 50px;
background-color: #008000;
z-index: 2;
}
...

I don't think you're far off. What I've done is create a second variable inside the mixin, called #index2. All this does is find the '920px minus #index' value that you're looking for:
#index2 = (920-#index);
this is then appended to the class name:
(~".gs#{index}-#{index2}") {
This is the complete loop:
.loopingClass (#index) when (#index > 160) {
#index2 = (920-#index);
// create the actual css selector, example will result in
// .myclass_30, .myclass_28, .... , .myclass_1
(~".gs#{index}-#{index2}") {
// your resulting css
width: (#index/20+1)*#col;
}
// next iteration
.loopingClass(#index - 60);
}
// "call" the loopingClass the first time with highest value
.loopingClass (#iterations);
In order to get just the set you are looking for (gs220-700 to gs700-220), just change #iterations to equal 700.
Worth noting that currently, this will create the classes in the reverse order of how you specified them in the question.

Related

ag-grid auto height for entire grid

I can't find a good way to size the grid to fit all rows perfectly.
documentation only points to sizing by % or px.
Since I want it to size based on rows, I came up with the following function. Seem like im re-inventing the wheel, so maybe there is a better way?
getHeight(type:EntityType) {
var c = this.Apis[type] && this.Apis[type].api && this.Apis[type].api.rowModel // get api for current grid
? this.Apis[type].api.rowModel.rowsToDisplay.length
: -1;
return c > 0
? (40+(c*21))+'px' // not perfect but close formula for grid height
: '86%';
}
there has to be a less messy way..
I came across this solution:
https://github.com/ag-grid/ag-grid/issues/801
There are 2 answers to this problem.
1) If you are using anything below v10.1.0, then you can use the following CSS to achieve the problem:
.ag-scrolls {
height: auto !important;
}
.ag-body {
position: relative !important;
top: auto !important;
height: auto !important;
}
.ag-header {
position: relative !important;
}
.ag-floating-top {
position: relative !important;
top: auto !important;
}
.ag-floating-bottom {
position: relative !important;
top: auto !important;
}
.ag-bl-normal-east,
.ag-bl-normal,
.ag-bl-normal-center,
.ag-bl-normal-center-row,
.ag-bl-full-height,
.ag-bl-full-height-center,
.ag-pinned-left-cols-viewport,
.ag-pinned-right-cols-viewport,
.ag-body-viewport-wrapper,
.ag-body-viewport {
height: auto !important;
}
2) Anything above v10.1.0, there is now a property called 'domLayout'.
https://www.ag-grid.com/javascript-grid-width-and-height/#autoHeight
If the following is the markup
<ag-grid-angular
#agGrid
id="myGrid"
class="ag-theme-balham"
[columnDefs]="columnDefs"
[rowData]="rowData"
[domLayout]="domLayout"
[animateRows]="true"
(gridReady)="onGridReady($event)"
></ag-grid-angular>
Note that [domLayout]="domLayout"
set it as this.domLayout = "autoHeight"; and you're done..
Ref:
https://www.ag-grid.com/javascript-grid-width-and-height/
https://next.plnkr.co/edit/Jb1TD7gbA4w7yclU
Hope it helps.
You can now automate grid height by setting the domLayout='autoHeight' property, or by calling api.setDomLayout('autoHeight')
reference Grid Auto Height
Add the following code on onGridReady function for auto width and auto height
onGridReady = params => {
// Following line to make the currently visible columns fit the screen
params.api.sizeColumnsToFit();
// Following line dymanic set height to row on content
params.api.resetRowHeights();
};
reference
Auto Height
Auto width
determineHeight() {
setTimeout(() => {
console.log(this.gridApi.getDisplayedRowCount());
if (this.gridApi.getDisplayedRowCount() < 20) {
this.gridApi.setDomLayout("autoHeight");
}
else {
this.gridApi.setDomLayout("normal");
document.getElementById('myGrid').style.height = "600px";
}
}, 500);
}
You can use ag-grid feature AutoHeight = true in the column Configuration. or if you want to calculate the height dynamically you should use getRowHeight() callback and create DOM elements like div and span, and add your text in it, then the div will give the OffsetHeight for it then you wont see any cropping of data/rows.
Hope this helps.

How to have an image span whole page in tumblr theme?

As the title says, I'm wondering how to get this image to span the whole browser window/page instead of having the gray margins.
Im using this theme:
https://raw.githubusercontent.com/olleota/themes/master/paperweight/main.html
And, its in action here:
http://fvcking5hit.tumblr.com/
where you see the gray borders and I just want it to span the whole page wile keeping the fade effect.
OK thank you for the additional comment, this should be all the code you need.
Find this code in your theme (it's showing at around line 226):
#masthead {
margin: 0 10%;
padding: 15% 0;
width: 80%;
}
Change it to:
#masthead {
margin: 0;
padding: 15% 0;
width:100%;
}
There are several references to #masthead in your css, so you will need to target the last reference for this to work (or tidy up the css by removing the old properties).
UPDATE
As you pointed out there is a media query changing the properties of the masthead.
Find this code:
#media (min-width: 1500px){
.theme-name-Paperweight #masthead {
margin: 0 20%;
width: 60%;
padding: 10% 0;
}
}
And change to:
#media (min-width: 1500px) {
.theme-name-Paperweight #masthead {
margin: 0;
width: 100%;
padding: 10% 0;
}
}

ng-class not evaluating the expression

I'm trying to implement ng-class in my angularJs application but for some reason expression in the ng-class is not getting applied, any thoughts?
<span>{{prod.item.count}}</span>
<div ng-class="{'show-error-box' : prod.item.length< 1}" class="hide-error-box">
prod is my controller alias in the view and item is the scope object in my controller
I want the class 'show-error-box' when the number of items is less than 1 otherwise apply the class hide-error-box. As I don't have any test data to test this with 0 length i'm replacing the expression with ng-class="{'show-error-box' : 0< 1}" in which case show-error-box should get applied, but it is not happening.
CSS:
.hide-error-box {
display:none;
}
.show-error-box {
float: left;
width: 100%;
background: #fff;
text-align: center;
padding: 10% 0;
height: 700px;
position: absolute;
}
ng-class does not serve as a replacement to "class". It will add any classes whose name is a key in your object if the associated value is true.
The only two options this div will have as a result are:
class="hide-error-box"
or
class="hide-error-box show-error-box"
To acheive the desired effect you would could put the opposite condition as a value of your hide class.
ng-class="{hide-error-box: prod.item.length >= 1, show-error-box: prod.item.length < 1}"
However, it is often recommended that you keep your templates as free from logic as possible. It may be worth considering placing this in a controller function:
HTML
<div class="{{getSizeClass()}}">
JS
this.getSizeClass = function() {
if (item.length >= 1) {
return 'hide-error-box'
}
return 'show-error-box'
}

SASS Mixin Arguments

I am passing multiple arguments in the mixin below. I am calling the mixin from multiple places in my CSS files; sometimes all the args need to be specified, other times only a few. Ruby allows you to pass an optional args using a hash. Is there such an equivalent in SASS, or this obviated by the fact that named arguments can be passed in any order, and arguments with default values can be omitted?
#mixin three-column-header-layout($background_color: #EEEEEE, $left_width: 25%, $mid_width: 50%, $right_width: 25%, $left_line_height: 40px, $mid_line_height: 40px, $right_line_height: normal, $column_height: 40px) {
.wrapper {
margin: 0 auto;
width: 100%;
overflow: hidden;
}
.middleCol {
float: left;
background: $background_color;
height: $column_height;
width: $mid_width;
display: inline;
line-height: $mid_line_height;
}
.leftCol {
background: $background_color;
height: $column_height;
width: $left_width;
float: left;
line-height: $left_line_height;
}
.rightCol {
background: $background_color;
height: $column_height;
width: $right_width;
float: left;
line-height: $right_line_height;
}
}
Sass's only data structure as of 3.1.7 is lists.
As you mentioned you can include your mixin using any combination of named arguments only if all arguments that are not passed have default values.
Sass 3.3 added the mapping data structure and you can pass them as arguments to mixins like this:
$options:
( background_color: red
, right_width: 30%
, left_width: 20%
);
.foo {
#include three-column-header-layout($options...);
}
Note, however, that one could also specify the arguments like so (this may have been a 3.2 feature):
.foo {
#include three-column-header-layout($background_color: red, $right_width: 30%, $left_width: 20%)
}

Can you use jQuery .css() with .live()?

I have a div with class="centerMessage" . This div is inserted into the DOM at a point after the page is loaded. I would like to change the CSS on this div to center it. I tried the CSS function below, but it did not work. Does anybody know a way to do this?
function centerPopup() {
var winWidth = $(window).width();
var winHeight = $(window).height();
var positionLeft = (winWidth/2) - (($('.centerMessage').width())/2);
var positionTop = (winHeight/2) - (($('.centerMessage').height())/2);
$('.centerMessage').live( function(){
$(this).css("position","absolute");
$(this).css("top",positionTop + "px");
$(this).css("left",positionLeft + "px");
});
}
If my assumption of what you're trying to achieve is correct, you don't need any Javascript to do this. It can be achieved by some simple CSS.
.centerMessage {
position: absolute;
top: 50%;
left: 50%;
margin-top: -150px; /* half of the height */
margin-left: -300px; /* half of the width */
width: 600px;
height: 300px;
background: #ccc;
}
Demo: http://jsbin.com/awuja4
.live() does not accept JUST a function. If you want something to happen with live, it needs an event as well, like click. If you want something to happen always for every .centerMessage, you will need the plugin .livequery()
I believe that the following works in FF & Webkit.
div.centerMessage{
position: absolute;
width: /* width */;
height: /* height */;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
margin: auto;
}
I know this is already answered, but I thought I'd provide a working jsFiddle demo using JavaScript like the OP originally wanted, but instead of using live(), I use setInterval():
First, we need to declare a couple variables for use later:
var $centerMessage,
intervalId;
The OP's issue was that they didn't know when the div was going to be created, so with that in mind we create a function to do just that and call it via setTimeout() to simulate this div creation:
function createDiv() {
$('<div class="centerMessage">Center Message Div</div>').appendTo("body");
}
$(function() { setTimeout("createDiv()", 5000); });
Finally, we need to create a function that will check, using setInterval() at a rate of 100ms, to see if the div has been created and upon creation, goes about modifying the div via jQuery:
function checkForDiv() {
$centerMessage = $('.centerMessage');
if ($centerMessage.length) {
clearInterval(intervalId);
var $window = $(window),
winHeight = $window.height(),
winWidth = $window.width(),
positionTop = (winHeight / 2) - ($centerMessage.height() / 2),
positionLeft = (winWidth / 2) - ($centerMessage.width() / 2);
$centerMessage.css({
"display" : "block",
"position" : "absolute",
"top" : positionTop.toString() + "px",
"left" : positionLeft.toString() + "px"
});
}
}
$(function() { intervalId = setInterval(checkForDiv, 100); });
Try Use this
$('.centerMessage').live('click', function(){
Try this
$('#foo').on('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');
OR
$('#foo').live('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');