jCarousel with unknown content width - javascript

I am trying to use jCarousel plugin for jQuery in order to provide my website users with scrollable (horizontal) content.
The content I am mentioning is basically user defined <li> elements, styled so that they have a feel and look of a tab. so basically I am trying to achieve the same effect of the tabs in pageflakes.com. As you may imagine, the users are creating tabs and providing tab names by themselves..
jCarousel needs you to specify a fixed width for the content e.g., all their examples are based upon images that have fixed height and width. but in my case I have not control over what the user will name his/her tab...making it impossible for me to guess the width of the total container div.
I have tried using a silly method such as guessing the width programatically assuming each letter being approx 5 pixels and multiplying 5 with the length of the word they have given as a name for a tab. even in this case, i needed to manipulate the css file dynamically which I am not sure how to do and even if it is feasable to do so..
Any solutions appreciated...
<lu>
<li class='MyTab' id='578'>This is my tab</li>
<li class='MyTab' id='579'>of which I can</li>
<li class='MyTab' id='580'>never guess</li>
<li class='MyTab' id='581'><img src='img/bullet_key.png' /> The length of</li>
</lu>
The above html is produced programatically through ajax_tabs_output.aspx, loaded into a javascript array and the jCarousel takes care of the rest..
function outputTabsArray() {
$.ajax({
url: 'ajax_tabs_output.aspx',
type: 'get',
data: 'q=array',
async: false,
success: function(out)
{
tabs_array = out;
}
});
}// end outputTabsArray
function mycarousel_itemLoadCallback(carousel, state)
{
for (var i = carousel.first; i <= carousel.last; i++) {
if (carousel.has(i)) {
continue;
}
if (i > tabs_array.length) {
break;
}
carousel.add(i, mycarousel_getItemHTML(tabs_array[i-1]));
}
};
/**
* Item html creation helper.
*/
function mycarousel_getItemHTML(item)
{
return '<div class="MyTab" id="' + item.tab_id + "'>" + item.tab_name + '</div>';
};
$('#mycarousel').jcarousel({
size: tabs_array.length,
itemLoadCallback: {onBeforeAnimation: mycarousel_itemLoadCallback}
});

The closest thing to what you want is probably jscrollhorizontalpane. I've never used it so I can't vouch for it's effectiveness as a solution to this specific problem.
This sort of widget shouldn't be to hard to make if you want to attempt it. I'll break down the approximate method I would use:
Make sure to use plenty of wrappers.
<div class="scrollable">
<div class="window">
<div class="space">
<ul class="tabs">
<li class="tab">...</li>
<li class="tab">...</li>
<li class="tab">...</li>
</ul>
</div>
</div>
←
→
</div>
What we'll be doing is shifting the "space" element back and forth inside "window" element. This can be done by setting position:relative to "window" and position:absolute to "space" and then shift it about using left:-??px, but I'll use the scrollLeft property.
Add some CSS.
.window {
overflow : hidden;
width : 100%;
}
.space {
width : 999em; /* lots of space for tabs */
overflow : hidden; /* clear floats */
}
.tabs {
float : left; /* shrink so we can determine tabs width */
}
.tab {
float : left; /* line tabs up */
}
This is just the basic stuff that the technique needs. Some of this stuff could be applied by jQuery,
Add events to window resize.
$(window)
.resize(function () {
var sz = $('.window');
var ul = sz.find('ul');
if ( sz.width() < ul.width() ) {
$('.scrollable a.left, .scrollable a.right').show();
}
else {
$('.scrollable a.left, .scrollable a.right').hide();
}
})
.trigger('resize');
Add events to scroll buttons.
$('.scrollable a.left').hover(
function (e) {
var sz = $('.window');
sz.animate({ scrollLeft : 0 }, 1000, 'linear');
},
function (e) {
$('.window').stop();
});
$('.scrollable a.right').hover(
function (e) {
var sz = $('.window');
var margin = sz.find('ul').width() - sz.width();
sz.animate({ scrollLeft : margin }, 1000, 'linear');
},
function (e) {
$('.window').stop();
});
Done!
The widths could also be calculated by looping through the "tab" elements and summing upp outerWidth. This is unnecessary if you have full control but might be a better choice for a full standalone plugin.

From what I can tell, you're trying make JCarousel do something it was never designed to do. Based on what I read on the JCarousel website it appears to be an image rotator.
What it sounds like you want is a tabbed interface. See JQuery UI Tabs for a demo and documentation on how to implement it.
If I'm totally wrong and all you're looking for is a tutorial on how to do proper CSS tabs, have a look at:
http://unraveled.com/projects/css_tabs/

Soviut,
You are actually quite right! I am trying to make JCarousel do something it wasn't designed for.
However, I also wouldn't like to use a tab plugin or any similar stuf as I NEED FULL CONTROL over my output. Such as injecting more elements into the tabs when needed such as double clicking, loading and many other etc. etc.
Actually what I am looking for a way to scroll horizontally the content within a div with arrows on the left and right.. To be more precise, I need the exact same structure of the tabs seen in www.pageflakes.com
The user will be able to create tabs by clicking on a link (or any other element for that matter), they will be able to inline edit its name, whenever they have more tabs then the length of the div, the buttons will be visible allowing them to slide inside the div, I will have events bound to their load, click and double click events.
To summarize I have everything ready and working except for the sliding/scrolling part. Its only I have to get help from you guys regarding how to achieve this functionality..
Kind regards,

What you're looking for isn't tabs, but draggable panels. One example can be found here, called JQuery Portlets. The related blog entry about Portlets can be found here.
You may also want to look into JQuery UI's Draggable, Droppable, and Sortable plugins.

Related

How can I make Owl Carousel dot navigation buttons accessible?

I'm trying to get rid of all of the issues reported by the Google Chrome Lighthouse Audit. I'm slowly progressing but I have a problem with 'accessible buttons'.
These buttons are the "dots navigation" from the Owl Carousel 2 library and it seems that they are not really accessible. This is the Lighthouse info:
When a button doesn't have an accessible name, screen readers announce it as "button", making it unusable for users who rely on screen readers.
Failing Elements
button.owl-dot.active
button.owl-dot
I can not really manipulate the code responsible for generating the dots-navbar and I'm wondering, what'd be the best approach in this case. I need to add the name attribute with the "Previous" and "Next" values I guess but should I add that attribute with JS ? Have You guys encountered such an issue with Owl 2 ? If so - please let me know because maybe there is another, better way to do that.
Best Regards,
Since it's a jQuery plugin I'd just use jQuery in the onInitialized and onResized callbacks to add offscreen text nodes to the buttons:
<style>
.offscreen {
position: absolute;
left: -999em;
}
</style>
<button><span></span><span class="offscreen">Go to slide 3</span></button>
<!-- the first span is there by default -->
That might look something like this:
let owl = $('.owl-carousel').owlCarousel({
// ...,
onInitialized: addDotButtonText,
onResized: addDotButtonText
});
function addDotButtonText() {
// loop through each dot element
$('.owl-dot').each(function() {
// remove old text nodes
$(this).find('.offscreen').remove();
// grab its (zero-based) order in the series
let idx = $(this).index() + 1;
// append a span to the button containing descriptive text
$(this).append('<span class="offscreen">Go to slide ' + idx + '</span>');
});
}
Fiddle demo
If you feel like the dots simply aren't useful to screen reader users, and are ok with them having only the previous and next buttons (which are already accessible) for navigation, you could effectively hide the dots to them in the callback and reduce unnecessary distraction:
$('.owl-dots').attr('aria-hidden', 'true');
This is probably a debatable strategy as we should strive to offer the same level of interaction to all users. However, since screen reader users may not have a use for slider controls to begin with, since all slides should be readable at all times, it's maybe not an issue at all.

vertically center page around a form

I know vertical center in CSS is a pain to begin with, but I've just made it a bit more complicated. On my page, I have:
<ul id="complete">
</ul>
<form id="new_item_form">
<input type="text" id="add_item" placeholder="Type some tasks here"/>
</form>
<ul id="incomplete">
</ul>
It's for a basic task list. Tasks are added to the incomplete ul, and when completed move to the complete ul. What I want to do via css is have the text field vertically centered on the page and stay there, with the two lists butted up against it. I've been looking at all sorts of vertical alignment (a summary of forms found here: http://blog.themeforest.net/tutorials/vertical-centering-with-css/ ) but I can't seem to find a way that I can figure out how to adapt to allow what I need. How would I accomplish this style of fixed position centering?
EDIT:
Here's an image of what I'm looking for: https://www.dropbox.com/s/i0oit3v84j93b5g/Screen%20Shot%202012-10-11%20at%204.27.16%20PM.png
Is this what you want to obtain?
Of course, my code is a bit sketchy (use of height attribute on tds! Don't scold me to much). But you get the point.
If the height of the table is not known nor fix, but its parent height is known, it won't work (see this example) and you'll have to break it down.
If you just don't know any height at all, it's kind of hard to align...
Further reading on vertical-align
I can't think of any way to do this with CSS, but it's fairly easy to do with JavaScript/jQuery. Here is a working jsFiddle that does what you want on document load. You'd call the code again if you changed the lists, of course.
First, you enclose your lists and form in a div. I called this id="cmiddle". Then you use CSS to set the cmiddle div as position: relative. Then you use JavaScript code to get the enclosing window or frame height, calculate the center for the form, and then, subtract the upper list height to get the correct div position:
$(document).ready(function(e) {
// To work with frames, too
function getParentDocHeight($ele) {
for (;;) {
if (!$ele || !$ele.length) {
return $(window).height();
}
$ele = $ele.parent();
if ($ele.is("frame") || $ele.is("window")) {
return $ele.height();
}
}
}
var $cm = $("#cmiddle");
var formHeight = $("#new_item_form").outerHeight();
var viewHeight = getParentDocHeight($cm)
var formTop = (viewHeight - formHeight) / 2;
var divTop = formTop - $("#complete").outerHeight();
$cm.css("top", divTop);
});
Edit: Kraz was nice enough to add a simulation of adding list items to both lists and calling the code again to recalc. His jsFiddle here.
Well, I'm not sure what you are talking about
But generally,
put the line-height = the div's height. I will create a div around it if necessary
if some very particular situations, i do some math to manually center it
So if you want to centering 1 thing, create a div go around it with line-height = the div's height
And then make the div position: absolute, width, height, ....
Hope this helps

achieving equal height columns in a responsive / flexible layout

I'm trying to achieve equal height columns on a 'responsive' website.
That means I'm using media queries to provide several layouts for one website depending on the size of the device and window.
I have 2 columns which need to have the same height. It's easy to achieve when the layout is fixed. I found dozens of scripts that do it and it works well.
However when I resize the browser window, that generated height doesn't change. So if the window is smaller, the height of the columns stays the same as before and the contents of the columns overflows. It's ugly.
Is there a way that generated height could change as I resize the window ?
Note : because of what's inside the columns I cannot use any CSS trick with backgrounds images etc. I really REALLY need both columns to truly have the same height at all times.
This question is already pretty old, but I didn't stumble upon a good solution for this myself until now.
A working solution would be a jQuery plugin that does something like setting the height of the columns to 'auto', measuring which one is the highest and set the columns to that height. Something along the lines of this:
$.fn.eqHeights = function (options) {
var $el = $(this),
$window = $(window),
opts = $.extend({}, $.fn.eqHeights.defaults, options);
if ($el.length > 0 && !$el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function () {
$el.eqHeights(opts);
});
$el.data('eqHeights', true);
}
return $el.each(function () {
var children = $(this).find(opts.childrenSelector);
if (!(opts.minWidth) || opts.minWidth < $window.width()) {
var curHighest = 0;
children.each(function () {
var $el = $(this),
elHeight = $el.height('auto').height();
if (elHeight > curHighest) {
curHighest = elHeight;
}
}).height(curHighest);
} else {
children.height('auto');
}
});
};
$.fn.eqHeights.defaults = {
childrenSelector: '*',
minWidth: ''
};
You can see this in action here: demo#codepen.io
The plugin supports two options:
childrenSelector: (Optional) The selector by which children that should get equal height are picked. Defaults to *, so everything in your parent is brought to equal height. Set to > to pick only direct children or something else to get the desired effect.
minWidth: (Optional) The minimum viewport width above width the Plugin is working and calculates equal heights for the seleted children. Below their height is set to auto. This comes in handy if at some point your containers are laid out below each other and shouldn't have an equal height. Empty and inactive by default.
While this is working very good in all browser with which I tested, it is a very hackish solution, so maybe someone here can propose something better. I thought about copying the columns and their wrapper to hidden container in the document, but this isn't any less clean and produces a way bigger footprint.
My favorite trick to creating equal height columns that work almost everywhere is to set "overflow:hidden" on a wrapper div, and setting a huge positive bottom padding and a negative bottom margin on the columns themselves. Now the columns will always be the full height of the wrapper, whatever the height of the wrapper is.
Viz -
<div class="wrapper">
<div class="column"> Column one content </div>
<div class="column"> Column two content </div>
</div>
<style type="text/css">
.wrapper {
overflow:hidden;
}
.column {
margin-bottom: -2000px;
padding-bottom: 2000px;
}
</style>
Here's a JSFiddle example - http://jsfiddle.net/yJYTT/
I wrote a small jQuery plugin for this: http://github.com/jsliang/eqHeight.coffee/
Tested it on Chrome, Firefox and IE9 and it works for me.
This works great! To make it work inside of a responsive layout you'll need to add the # media query so it's only used on screen sizes "larger than" your break point. Otherwise, the sidebar color extends down into the main content on the tablet and phone views. Here's how it looks in a responsive stylesheet:
div.wrapper {
overflow:hidden;
}
.column {
background-color: rgba(193,204,164,.5);
padding:2%;
margin-bottom: -2000px;
padding-bottom: 2000px;
}
#media screen and (max-width:960px){
.column {padding-bottom:2%; margin-bottom:0px;}
}
I hacked the solution even further from boundaryfunctions's answer to take into consideration responsive layouts where the panels reflow above each other.
By checking each one against the first one's offset.top I was able to detect the orientation of the panels and resize their .panel-body element or assign an auto heigh for reflowed panels.
(function($) {
$.fn.eqHeights = function() {
var el = $(this);
if (el.length > 0 && !el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function() {
el.eqHeights();
});
el.data('eqHeights', true);
}
var panels = el.find(".panel-body");
var fistoffset = panels.first().offset();
var curHighest = 0;
return panels.each(function() {
var thisoffset = $(this).offset();
var elHeight = $(this).height('auto').height();
if(thisoffset.top==fistoffset.top){
if (elHeight > curHighest) {
curHighest = elHeight;
}
}else{
curHighest = "auto";
}
}).height(curHighest);
};
}(jQuery));
$('.match_all').eqHeights();
Example here: http://bootply.com/render/104399
Some time after the question I know - but for reference - last time I had to solve this problem I hacked this jquery code to a plugin:
http://css-tricks.com/equal-height-blocks-in-rows/
obviously $(window).resize is the crucial part - as it'll re-conform the heights once the re-size has taken place. Taking it a step further I always meant to look into 'de-bouncing' the column reconform to help with performance:
http://paulirish.com/2009/throttled-smartresize-jquery-event-handler/
but never got that far.
I had the same problem. After some research I selected the faux column technique. Check this blog post that I wrote on how to make it work in a responsive design.
Responsive full height (equal height) columns using the faux columns technique

JQuery Sortable Grid Functionality without Identical Dimensions

I am looking to create a sortable (via drag and drop) grid, similar to what JQuery's Sortable grid does ( http://jqueryui.com/demos/sortable/#display-grid ). However, Sortable requires that you use only divs with identical dimensions. For my purposes, each block is allowed to be different widths and heights.
The functionality I am looking for is the snap-to-grid capabilities while "shoving" the other elements out of the way. Draggable does everything except for preventing them from overlapping and shoving the other elements out of the way.
Oh, it doesn't have to be Jquery either. I'm open to using other methods if it is easier.
Jquery sortable does not require the items to be the same dimensions, as you can see in my prototype here: http://brettlyman.net/dashboard/index3.html
Most people use <ul> as the sortable container and <li>'s as the sortable items, and they can contain any content you want. Just make sure you put "list-style-type: none; margin: 0; padding: 0;" in the style of the <ul> so it looks/behaves like a container.
Unfortunately with sortable you cannot do a free-form grid -- the items must be next to each other in proximity. In my prototype I float everything left, so they fill to the right and then drop to the next line. I have the grid option set on the resize of my containers, however, so I can enforce a grid-type layout.
Thought I'd post my solution in case anyone else is having the same type of problem.
The short answer:
use "stop" event to re-calculate all grid elements according their new positions.
General comments:
sortable grid with variable element's dimensions - it is a visual mess, as elements of different size moving multiple times, jumping up and down, while you're dragging one of them; and layout completely different after each movement.
Working on the similar feature I developed jQuery plugin "Swappable"
http://www.eslinstructor.net/demo/swappable/swappable_home.html
and recently I answered the same question regarding this plugin:
to Swap elemnts(with className too) when Draged & Dropped
please take a look at the discussion and maybe it help you.
best regards,
-Vadim
I came across this question trying to solve the problem for myself.
I'm on my first iteration at trying a workaround: use the parent container as a droppable. Will let you know if it works:
For the following HTML:
<div id="sortable">
<div><div class="handle"></div>1</div>
<div><div class="handle"></div>2</div>
<div><div class="handle"></div>3</div>
...
</div>
Using the following JavaScript:
$('#sortable')
.sortable({
handle: '.handle',
tolerance: 'pointer'
})
.droppable({
drop: function(e, ui) {
var previousElement = ui.draggable.parent().children().filter(function() {
var $this = $(this);
var pos = $this.position();
return (this != ui.draggable[0]) && (pos.left <= ui.position.left) && (pos.top <= ui.position.top);
}).last();
if( previousElement.length ) {
previousElement.after(ui.draggable[0]);
ui.draggable.parent().data().sortable._noFinalSort = true;
}
}
});

Scrollable div without overflow:auto?

In my app I have 2 divs, one with a long list of products that can be dragged into another div (shopping cart). The product div has the overflow but it breaks prototype draggable elements. The prototype hacks are very obtrusive and not compatible with all browsers.
So I am taking a different approach, is it possible to have a scrollable div without using CSS overflow:auto?
Theres a css property to control that.
<div style="width:100px;height:100px;overflow:scroll">
</div>
http://www.w3schools.com/Css/pr_pos_overflow.asp
You can use a frame with content larger than its window. Might make it hard to pass JS events though.
Here is what I wrote to have it running under IE 8.0.6 & Firefox 3.6.3:
Make draggable the elements (with border) in the "width:100px;scrollable:auto" container:
function makeDraggable(container,tag) {
if(!container || !tag) { return false; }
$(container).select(tag).each( function(o) {
new Draggable(o,{
starteffect: function(e){makeDragVisible(container,e);},
endeffect: function(e){e.setStyle({'position':'','width':'','cursor':''});},
zindex: 1000
// , revert: ... // the other options
});
});
}
function makeDragVisible(container,element) {
if(!container || !element) { return false; }
var i=$(container).getStyle('width');
i=i.replace('px','');
i=Math.round(i-20)+'px';
element.setStyle({'width':i,'z-index':1000,'position':'absolute','cursor':'move'});
//
$(container).setStyle({});
}
Important notes:
the z-index is repeated
notice the container loss of style at the end of 'starteffect'. Cursor and width are simply there to keep the drag user friendly.
I hope it helps.

Categories