Messy but Working jQuery - javascript

I've written the jQuery you'll see below for a little project I'm working on. It works perfectly and is all set, but, as you can see, it's messy and kind of...long winded.
I've tried a bunch of different ways to clean this up but I'm not just ninja-like enough to really neaten it up. Any advice? Thanks in advance guys!
var colspan = $(".col header span"),
rowspan = $(".row header span"),
topspan = $(".top header span");
var colh2 = $(".col header h2").h2width();
var rowh2 = $(".row header h2").h2width();
var toph2 = $(".top header h2").h2width();
var colwidth = 820 - colh2;
var rowwidth = 820 - rowh2;
var topwidth = 820 - toph2;
colspan.css({float: 'left', width: colwidth});
rowspan.css({float: 'left', width: rowwidth});
topspan.css({float: 'left', width: topwidth});

["col", "row", "top"].forEach(function (className) {
var str = "." + className + " header";
var h2s = document.querySelectorAll(str + " h2");
var spans = document.querySelectorAll(str + " span");
var width = 820 - h2width(h2s);
Array.prototype.forEach.call(spans, function (span) {
span.style.float = "left";
span.style.width = width;
});
});
Because jQuery is always overkill.

I would do it like this maybe? shorter but maybe not as well documented:
$(".col header span, .row header span, .top header span").each(function(){
$(this).css({
float: 'left',
width: 820 - $(this).siblings("h2").width()
});
});

I would probably rewrite your code in the following way:
var conts = {
'col': jQuery('.col header'),
'row': jQuery('.row header'),
'top': jQuery('.top header')
};
jQuery.each(conts, function(index, val){
val.find('span').css({
'float': 'left',
'width': 820-val.find('h2').h2width()
});
});
This uses caching the main elements and then will iterate on all of them applying the similar actions.
See more information on jQuery's .each() function.
EDIT: Or even shorter:
jQuery('.col header, .row header, .top header').each(function(){
var current = jQuery(this);
current.find('span').css({
'float': 'left',
'width': 820 - current.find('h2').h2width()
});
});

Simply get rid of the duplicate code:
$.each(['.col', '.row', '.top'], function(i, cls) {
var width = $(cls + ' header h2').h2width();
$(cls + ' header span').css({
float: 'left',
width: 820 - width
});
});

Just use a function:
function updateStyle(name){
var headerSpan = $('.' + name + ' header span');
var headerH2 = $('.' + name + ' header h2');
headerSpan.css({float: 'left', width: 820 - headerH2.h2width()});
}
updateStyle('col');
updateStyle('row');
updateStyle('top');

Related

Create jQuery infinite loop of items

I am trying to accomplish an infinite loop of items inside 1 main div.
The idea is to show part of the items, then slide the left one outside of the screen, whilst another is added from the right side of the screen.
The following function is working, but the animate method doesn't work, it just changing the css without animating it.
Am I doing it wrong?
Also any better approach would be welcome. I tried to search jQuery solutions but they didn't work well for me so i wanted to create another one.
jQuery(document).ready(function() {
var items = jQuery('.companies-logos div');
var temp;
var item_width = 0;
if(items.length > 9) {
items.slice(9).remove();
setInterval(function(){
jQuery('.companies-logos').append(items[9]);
items[9].style.marginLeft = '0';
item_width = items[0].offsetWidth + 12.5;
jQuery(items[0]).animate({marginLeft: '-' + item_width + 'px'}, 2000);
// items[0].style.marginLeft = '-' + item_width + 'px';
temp = items[0];
jQuery(items[0]).remove();
items.splice(0, 1);
items.push(temp);
// jQuery(items[items.length-1]).css('transition', 'all 2500ms');
}, 2500);
}
});
For those interested in achieving the wanted result from above:
$(function(){
setInterval(function(){
var item_width = $('.companies-logos ul li:first-child').width() + 25;
$(".companies-logos ul li:first-child").animate({"margin-left": -item_width}, 1500, function(){
$(this).css("margin-left",25).appendTo(".companies-logos ul");
});
}, 2000);
});

ScrollFire Materialize reveal List

Hi i am looking for a possible solution for the following problem.
I am building a website and i have a table which has many many rows.
I am using materialize (but if there is another plugin that can do it i am open for it).
Materialize uses this
var options = [
{selector: '#staggered-test', offset: 50, callback: function(el) {
Materialize.toast("This is our ScrollFire Demo!", 1500 );
} },
{selector: '#staggered-test', offset: 205, callback: function(el) {
Materialize.toast("Please continue scrolling!", 1500 );
} },
{selector: '#staggered-test', offset: 400, callback: function(el) {
Materialize.showStaggeredList($(el));
} },
{selector: '#image-test', offset: 500, callback: function(el) {
Materialize.fadeInImage($(el));
} }
];
Materialize.scrollFire(options);
But how to implement it on table rows?
I would simply like to hide most of the rows but get visible the more the user scrolls down.
Is this possible?
Thanks
Instead of scroll i made a button to show more using javascript and jquery here is the function
$.fn.RowReveal = function(RowsToShow, numMore) {
var numShown = RowsToShow;
var numMore = numMore;
var $table = $(this).find('tbody');
var numRows = $table.find('tr').length;
var btn_id = parseInt(Math.random()*1000)+numRows;
// Hide rows and add clickable div
$table.find('tr:gt(' + (numShown - 1) + ')').hide().end()
.after('<tbody id="more-'+btn_id+'"><tr><td colspan="' +
$table.find('tr:first td').length + '"><div>Show More</div></tbody></td></tr>');
$('#more-'+btn_id).click(function () {
numShown = numShown + numMore;
if (numShown >= numRows) {
$('#more-'+btn_id).remove();
}
if (numRows - numShown < numMore) {
$('#more-'+btn_id+' span').html(numRows - numShown);
}
$table.find('tr:lt(' + numShown + ')').fadeIn();
});
}

Text pagination inside a DIV with image

I want to paginate a text in some div so it will fit the allowed area
Logic is pretty simple:
1. split text into words
2. add word by word into and calculate element height
3. if we exceed the height - create next page
It works quite good
here is JS function i've used:
function paginate() {
var newPage = $('<pre class="text-page" />');
contentBox.empty().append(newPage);
var betterPageText='';
var pageNum = 0;
var isNewPage = false;
var lineHeight = parseInt(contentBox.css('line-height'), 10);
var wantedHeight = contentBox.height() - lineHeight;
for (var i = 0; i < words.length; i++) {
if (isNewPage) {
isNewPage = false;
} else {
betterPageText = betterPageText + ' ' + words[i];
}
newPage.text(betterPageText + ' ...');
if (newPage.height() >= wantedHeight) {
pageNum++;
if (pageNum > 0) {
betterPageText = betterPageText + ' ...';
}
newPage.text(betterPageText);
newPage.clone().insertBefore(newPage)
betterPageText = '...';
isNewPage = true;
} else {
newPage.text(betterPageText);
}
}
contentBox.craftyslide({ height: wantedHeight });
}
But when i add an image it break everything. In this case text overflows 'green' area.
Working fiddle: http://jsfiddle.net/74W4N/7/
Is there a better way to paginate the text and calculate element height?
Except the fact that there are many more variables to calculate,not just only the word width & height, but also new lines,margins paddings and how each browser outputs everything.
Then by adding an image (almost impossible if the image is higher or larger as the max width or height) if it's smaller it also has margins/paddings. and it could start at the end of a line and so break up everything again.basically only on the first page you could add an image simply by calculating it's width+margin and height+margin/lineheight. but that needs alot math to get the wanted result.
Said that i tried some time ago to write a similar script but stopped cause of to many problems and different browser results.
Now reading your question i came across something that i read some time ago:
-webkit-column-count
so i made a different approach of your function that leaves out all this calculations.
don't judge the code as i wrote it just now.(i tested on chrome, other browsers need different prefixes.)
var div=document.getElementsByTagName('div')[0].firstChild,
maxWidth=300,
maxHeigth=200,
div.style.width=maxWidth+'px';
currentHeight=div.offsetHeight;
columns=Math.ceil(currentHeight/maxHeigth);
div.style['-webkit-column-count']=columns;
div.style.width=(maxWidth*columns)+'px';
div.style['-webkit-transition']='all 700ms ease';
div.style['-webkit-column-gap']='0px';
//if you change the column-gap you need to
//add padding before calculating the normal div.
//also the line height should be an integer that
// is divisible of the max height
here is an Example
http://jsfiddle.net/HNF3d/10/
adding an image smaller than the max height & width in the first page would not mess up everything.
and it looks like it's supported by all modern browsers now.(with the correct prefixes)
In my experience, trying to calculate and reposition text in HTML is almost an exercise in futility. There are too many variations among browsers, operating systems, and font issues.
My suggestion would be to take advantage of the overflow CSS property. This, combined with using em sizing for heights, should allow you to define a div block that only shows a defined number of lines (regardless of the size and type of the font). Combine this with a bit of javascript to scroll the containing div element, and you have pagination.
I've hacked together a quick proof of concept in JSFiddle, which you can see here: http://jsfiddle.net/8CMzY/1/
It's missing a previous button and a way of showing the number of pages, but these should be very simple additions.
EDIT: I originally linked to the wrong version for the JSFiddle concept
Solved by using jQuery.clone() method and performing all calculations on hidden copy of original HTML element
function paginate() {
var section = $('.section');
var cloneSection = section.clone().insertAfter(section).css({ position: 'absolute', left: -9999, width: section.width(), zIndex: -999 });
cloneSection.css({ width: section.width() });
var descBox = cloneSection.find('.holder-description').css({ height: 'auto' });
var newPage = $('<pre class="text-page" />');
contentBox.empty();
descBox.empty();
var betterPageText = '';
var pageNum = 0;
var isNewPage = false;
var lineHeight = parseInt(contentBox.css('line-height'), 10);
var wantedHeight = contentBox.height() - lineHeight;
var oldText = '';
for (var i = 0; i < words.length; i++) {
if (isNewPage) {
isNewPage = false;
descBox.empty();
}
betterPageText = betterPageText + ' ' + words[i];
oldText = betterPageText;
descBox.text(betterPageText + ' ...');
if (descBox.height() >= wantedHeight) {
if (i != words.length - 1) {
pageNum++;
if (pageNum > 0) {
betterPageText = betterPageText + ' ...';
}
oldText += ' ... ';
}
newPage.text(oldText);
newPage.clone().appendTo(contentBox);
betterPageText = '... ';
isNewPage = true;
} else {
descBox.text(betterPageText);
if (i == words.length - 1) {
newPage.text(betterPageText).appendTo(contentBox);
}
}
}
if (pageNum > 0) {
contentBox.craftyslide({ height: wantedHeight });
}
cloneSection.remove();
}
live demo: http://jsfiddle.net/74W4N/19/
I actually came to an easier solution based on what #cocco has done, which also works in IE9.
For me it was important to keep the backward compatibility and the animation and so on was irrelevant so I stripped them down. You can see it here: http://jsfiddle.net/HNF3d/63/
heart of it is the fact that I dont limit height and present horizontal pagination as vertical.
var parentDiv = div = document.getElementsByTagName('div')[0];
var div = parentDiv.firstChild,
maxWidth = 300,
maxHeigth = 200,
t = function (e) {
div.style.webkitTransform = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
div.style["-ms-transform"] = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
};
div.style.width = maxWidth + 'px';
currentHeight = div.offsetHeight;
columns = Math.ceil(currentHeight / maxHeigth);
links = [];
while (columns--) {
links[columns] = '<span>' + (columns + 1) + '</span>';
}
var l = document.createElement('div');
l.innerHTML = links.join('');
l.onclick = t;
document.body.appendChild(l)

How to append text to div

Hi i have written this code to take 3 parameters and assign to variable.now i want to append the text i am getting throughparameter to div fontdiv
how to do this?
here is what i have tried..
function getTextWidth(text, fontname, fontsize) {
var elem = '<div id="fontdiv" style="position: absolute;visibility: visible;height: auto;"></div>';
$('body').append($(elem));
var fontdiv = document.getElementById('fontdiv');
fontdiv.style.fontSize = fontsize;
fontdiv.style.fontFamily = fontname;
$("#fontdiv").html($('text').val());
return fontdiv.clientWidth;
};
If your text param already has text
$("#fontdiv").append(text); // append text into fontdiv
If the value of text is set already (and it seems to be), use :
$("#fontdiv").append(text);
And it should work.
Use
function getTextWidth(text, fontname, fontsize) {
var elem = '<div id="fontdiv" style="position: absolute;visibility: visible;height: auto;"></div>';
var el = $(elem).append(text);
$('body').append(el);
var fontdiv = document.getElementById('fontdiv');
fontdiv.style.fontSize = fontsize;
fontdiv.style.fontFamily = fontname;
$("#fontdiv").html($('text').val());
return fontdiv.clientWidth;
};
Another way could be
function getTextWidth(text, fontname, fontsize) {
var el = $('<div>', {
id: 'fontdiv'
}).css({
position: 'absolute',
visibility: 'visible',
height: 'auto',
fontSize: fontsize,
fontFamily: fontname
}).append(text).appendTo('body');
return el.get(0).clientWidth;
};
Replace
$('body').append($(elem));
with
$('body').append(elem);

Storing an inline style into jquery variables

I have the following img tag,
<img id="image1" src="URL" alt="image1" name="image1" width="137" height="119" border="0" style="position: relative; left: -355px; top: 62px;" >
I would like to somehow, onclick, store the following items into seperate variables..
style="position: relative; left: -355px; top: 62px;"
var left = -355px
var top = 62px
Is that possible? Thank you!
Of course this is possible, have you tried something like this:
$('#image1').on('click', function () {
var style = 'style="' + $(this).attr('style') + '"';
var left = $(this).css('left');
var top = $(this).css('top');
alert(style);
alert(left);
alert(top);
});
Example: http://jsfiddle.net/9ZXHX/
var imageInfo = {style:null, left:null, top:null};
$('#image1').on('click', function() {
var $this = $(this);
imageInfo.style = $this.attr('style');
imageInfo.left = $this.css('left');
imageInfo.top = $this.css('top');
console.log('Image Clicked: ', imageInfo);
});
You could get the image with jquery, and then access its attributes from there.
var img = $("#image1");
var imgStyle = img[0].getAttribute("style");
var imgLeft = img.css("left");
var imgRight = img.css("right");
link to jquery's api for css: http://api.jquery.com/css/
In a function:
function getDetails(imgId)
{
var imgDetails = {};
var img = $("#"+imgId);
imgDetails.imgStyle = img[0].getAttribute("style");
imgDetails.imgLeft = img.css("left");
imgDetails.imgRight = img.css("right");
return imgDetails;
}
Here is a fiddle showing an example of this working, and the requested output in the question: http://jsfiddle.net/j7eYf/1/
I suggest your use jquery, it will make the job a lot easier. Try out this example,
$("#your trigger").live('click',function ()
{
$("#image1").css({
position: "absolute",
top: 62 + "px",
left: -355 + "px"
});
});

Categories