I have a dropdown menu container that is styled using flexbox. I have a vertical pipe after each list item and want to remove the pipe from the last item before the line break so as to avoid the dangling "|".
Any css wizardry to make this happen?
Here is the staging site: https://myersbrierkelly.djykrmv8-liquidwebsites.com/
Click on "Practice Areas" and you will see it on the dropdown.
.navbar .dropdown-menu li:last-child::after {
content: '';
}
I ended up having to go the javascript route by comparing each list item's offset top and finding the break based on that and adding a class of wrapped.
var detectWrap = function(className) {
var wrappedItems = [];
var prevItem = {};
var currItem = {};
var items = document.getElementsByClassName(className);
for (var i = 0; i < items.length; i++) {
currItem = items[i].getBoundingClientRect();
if (prevItem && prevItem.top < currItem.top) {
wrappedItems.push(items[i]);
}
prevItem = currItem;
};
return wrappedItems;
}
window.onload = function(e){
var wrappedItems = detectWrap('menu-item-object-practice-area');
for (var k = 0; k < wrappedItems.length; k++) {
wrappedItems[k].className = "wrapped";
}
};
Use nth-child(n) to select specific child element where you don't want the vertical pipe, like this
.navbar .dropdown-menu li:nth-child(4)::after,
.navbar .dropdown-menu li:nth-child(7)::after,
.navbar .dropdown-menu li:nth-child(10)::after {
content: "";
}
The nth-child(n) selector selects the nth child element.
Related
I have a "Loading" dialog that displays while I'm adding a lot of custom elements to a container. I've set the dialog to disappear when the last added element's creationCompleteHandler is called, but the dialog disappears before all the elements display on screen (which results in a very large lag).
Here's an example of what I'm doing:
for (var i:int = 0; i < 100; i++) {
var elem:MyElement = new MyElement();
elem.name = "elem" + i;
container.addElement(elem);
if (i == 99) {
elem.creationComplete = function():void {
PopUpManager.removePopUp(loadingDialog);
};
}
}
So as I've said, the dialog disappears before all the elements appear on screen. Is there a way to tell when all the custom elements have been added AND are currently showing on screen?
Update: To clarify, elem.creationComplete is just a custom property function that gets called when the element's creationCompleteHandler is called.
The elements, even though they have been added in the right order, they are not created in that order:
private function doStuff():void {
PopUpManager.addPopUp(myPopup, this);
for (var i:int = 0; i < 10; i++) {
var elem:MyElement = new MyElement();
elem.name = "elem" + i;
container.addElement(elem);
elem.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void {
trace("i'm done " + e.target.name);
});
if (i == 9) {
elem.addEventListener(FlexEvent.CREATION_COMPLETE, function():void {
trace("i'll remove the popup " + elem.name);
PopUpManager.removePopUp(myPopup);
});
}
}
}
Gives:
i'm done elem5
i'm done elem7
i'm done elem0
i'm done elem8
i'm done elem6
i'm done elem3
i'm done elem9
i'll remove the popup elem9
i'm done elem1
i'm done elem4
i'm done elem2
You need to add a global variable to check that all the elements have actually been created:
public var created:int = 0;
private function doStuff():void {
PopUpManager.addPopUp(myPopup, this);
for (var i:int = 0; i < 10; i++) {
var elem:MyElement = new MyElement();
elem.name = "elem" + i;
container.addElement(elem);
created++; // <--- increment with each new element
elem.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void {
created--; // <--- decrement when element is created
trace("i'm done ", e.target.name);
if (created == 0) {
trace("i'll remove it ", e.target.name);
PopUpManager.removePopUp(myPopup);
}
});
}
}
And the result is:
i'm done elem5
i'm done elem7
i'm done elem0
i'm done elem8
i'm done elem6
i'm done elem3
i'm done elem9
i'm done elem1
i'm done elem4
i'm done elem2
i'll remove it elem2
To solve this, I followed jidma's answer, except I listened for the PropertyChanged event and decremented when the contentHeight property changed on the container. This decremented only when the container's height was affected by the added element, which seemed to work.
Is there a CSS selector for the first element of every visual row of block items?
That is, imagine having 20 block elements such that they flow across multiple lines to fit in their parent container; can I select the leftmost item of each row?
It's doable in JavaScript by looking at the top position of all of the elements, but is it possible in plain CSS?
Yes, Its possible through CSS but only if you can fix the elements in every row.
Since you haven't provided your case, here is an example.
Suppose, your elements are stacked up in a ul and li pattern and are three lists in a row, then you can use the following css snippet.
li:first-child, li:nth-child(3n+1) {
background: red;
}
Demo
No, there is no selector for this, you'll need to use JavaScript.
For reference, the following is a good reference to CSS selectors:
http://www.w3.org/wiki/CSS/Selectors
Unfortunately this is not possible with CSS alone. I ran into this issue when I wanted to ensure that the left most floated elements on each row always start on a new line.
I know you were looking for a CSS solution but I wrote this jQuery plugin that identifies the first element on each visual row and applies "clear:left" to it (you could adapt it to do anything).
(function($) {
$.fn.reflow = function(sel, dir) {
var direction = dir || 'both';
//For each conatiner
return this.each(function() {
var $self = $(this);
//Find select children and reset clears
var $elems = sel ? $self.find(sel) : $self.children();
$elems.css('clear', 'none');
if ($elems.length < 2) { return; }
//Reference first child
var $prev = $elems.eq(0);
//Compare each child to its previous sibling
$elems.slice(1).each(function() {
var $elem = $(this);
//Clear if first on visual row
if ($elem.position().top > $prev.position().top) {
$elem.css('clear', direction);
}
//Move on to next child
$prev = $elem;
});
});
};
})(jQuery);
See this codepen example http://codepen.io/lukejacksonn/pen/EplyL
Based on the work by #lukejacksonn
This one adds or removes a class on window resize.
(function ($) {
$.fn.reflow = function (sel, className) {
if (className == null) throw new Error('className must be set');
//For each conatiner
return this.each(function () {
var $self = $(this);
//Find select children and reset clears
var $elems = sel ? $self.find(sel) : $self.children();
if ($elems.length < 2) {
return;
}
//Reference first child
var $prev = $elems.eq(0);
$elems.each(function () {
$(this).removeClass(className);
});
//Compare each child to its previous sibling
$elems.slice(1).each(function () {
var $elem = $(this);
//Clear if first on visual row
if ($elem.position().top > $prev.position().top) {
$elem.addClass(className);
}
//Move on to next child
$prev = $elem;
});
});
};
const markFirstRowElement = function () {
$(".cd-progress-indicator").reflow('li', 'first-row-element');
}
$(function () {
markFirstRowElement();
$(window).resize(markFirstRowElement);
});
})(jQuery);
I've got a whole bunch of rects on my canvas.
I'd like to change the stroke on whatever rect the user clicks, as well as running some other javascript. My simplified code is below.
var canvas = Raphael("test");
var st = canvas.set();
for (var i = 0; i < 2; i++) {
var act = canvas.rect(///edited for brevity////).attr({"stroke":"none"});
st.push(act)
act.node.onclick = function() {
st.attr({stroke: "none"});
act.attr({stroke: "yellow"});
}
}
Right now, no matter what rect I click on, it's only changing the stroke on the last rect drawn.
Any ideas?
Not a Raphaƫl problem but rather lack of closure understanding. Easily could be fixed by self invoking function:
for (var i = 0; i < 2; i++) {
var act = canvas.rect(///edited for brevity////).attr({"stroke":"none"});
st.push(act)
(function (act) {
act.node.onclick = function() {
st.attr({stroke: "none"});
act.attr({stroke: "yellow"});
}
})(act);
}
//Try and then embellish
st[i].click(function (e)
{
this.attr({stroke: "yellow"});
}
I have a div with absolute positioning set to allow vertical scrolling. My app includes drag & drop facilities that rely on me determining the coordinates of elements when events are fired.
The offsets I use to calculate elements positions (i.e. element.offsetLeft & element.offsetTop) only relate to original position of the element and do not account for changes in position that result from the user having scrolled. I figured I could add in a correction if I could calculate the distance scrolled but I can't see any way to do that (unlike with window scrolling).
Would really appreciate any suggestions.
Take a look at the scrollTop and scrollLeft properties of the div container.
Here's a cross-browser solution that finds an element's position taking into account scrolling div/s and window scroll:
var isIE = navigator.appName.indexOf('Microsoft Internet Explorer') != -1;
function findElementPosition(_el){
var curleft = 0;
var curtop = 0;
var curtopscroll = 0;
var curleftscroll = 0;
if (_el.offsetParent){
curleft = _el.offsetLeft;
curtop = _el.offsetTop;
/* get element scroll position */
var elScroll = _el;
while (elScroll = elScroll.parentNode) {
curtopscroll = elScroll.scrollTop ? elScroll.scrollTop : 0;
curleftscroll = elScroll.scrollLeft ? elScroll.scrollLeft : 0;
curleft -= curleftscroll;
curtop -= curtopscroll;
}
/* get element offset postion */
while (_el = _el.offsetParent) {
curleft += _el.offsetLeft;
curtop += _el.offsetTop;
}
}
/* get window scroll position */
var offsetX = isIE ? document.body.scrollLeft : window.pageXOffset;
var offsetY = isIE ? document.body.scrollTop : window.pageYOffset;
return [curtop + offsetY,curleft + offsetX];
}
This is what I'm implementing as a correction in case anyone's interested.
Thanks guys.
/*
Find a html element's position.
Adapted from Peter-Paul Koch of QuirksMode at http://www.quirksmode.org/js/findpos.html
*/
function findPos(obj)
{
var curleft = 0;
var curtop = 0;
var curxscroll = 0;
var curyscroll =0;
while(obj && obj.offsetParent)
{
curyscroll = obj.offsetParent.scrollTop || 0;
curxscroll = obj.offsetParent.scrollLeft || 0;
curleft += obj.offsetLeft - curxscroll;
curtop += obj.offsetTop - curyscroll;
obj = obj.offsetParent;
}
return [curleft,curtop];
}
In an ASP.NET web app, I am trying to create and populate a UL based on user input. This is not a quick fill. User enters a couple of letters, clicks a button, and the server returns all records like the entry. If there is more than one match, an UL is created showing all of the matches.
I've tried to adapt this code from a plugin. I can step through it with the debugger and everything seems OK, but the UL is either not generated to the document or it is invisible.
Here is the simplified code:
function fillBusinessDropdown(ListOfBusinesses) {
var results = document.createElement("div");
var $results = $(results);
$results.hide().addClass("ac_results").css("position", "absolute");
if ($.browser.msie) {
$results.append(document.createElement('iframe'));
}
results.appendChild(businessToDom(ListOfBusinesses));
$results.css({
width: 400 + "px",
top: 100 + "px",
left: 150 + "px"
}).show();
function businessToDom(ListOfBusinesses) {
var ul = document.createElement("ul");
var iLen = ListOfBusinesses.length - 1
for (var i = 0; i <= iLen; i++) {
var row = ListOfBusinesses[i];
if (!row) continue;
var li = document.createElement("li");
// add the business name
li.innerHTML = row.Bu_name;
// add the business ID
li.selectValue = row.Bupk;
var extra = null;
if (row.length > 1) {
extra = [];
for (var j = 1; j < row.length; j++) {
extra[extra.length] = row[j];
}
}
li.extra = extra;
ul.appendChild(li);
$(li).hover(
function() { $("li", ul).removeClass("ac_over");
$(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); },
function() { $(this).removeClass("ac_over"); }
).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this) });
}
return ul;
}
I am stumped. Does any0oe have any ideas where I've gone wrong?
Thanks
Mike Thomas
Not sure what is wrong with that code but you are using a mixture of javascript and Jquery. I suggest use JQuery all the time instead. Use .appendTo() etc