Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abilities of the 0.3 branch #352

Closed
Dupond opened this issue Mar 25, 2012 · 54 comments
Closed

Abilities of the 0.3 branch #352

Dupond opened this issue Mar 25, 2012 · 54 comments

Comments

@Dupond
Copy link

Dupond commented Mar 25, 2012

I'd like to convert my carousels to 0.3 branch, in order to fix my focus problems, and the resize problems under Chrome, as discussed in several issues here.

Is there some kind of know limitations with this branch, compared to the 0.2.8 one ? For example :

  • I'd need to configure a carousel with dynamic content loading from a PHP script. Is is still possible using 0.3 ? Which element event should I use to replace the "itemLoadCallback" event ?
  • Is the 0.2.8 focus issue solved in 0.3 ?

Furthermore, I've put my config code in an external file : should I use $(document).ready() (as I used to with 0.2.8) ? For the moment, I just have the following code in my config file :

$(function() { $('#carousel-editos').jcarousel()
    .find('[tabindex]')
    .focus(function(e) { e.preventDefault(); e.stopPropagation(); $(this).closest('.jcarousel').jcarousel('scroll', this); });
});

Is that fine ?

Thanx for your help,
Dupond

@jsor
Copy link
Owner

jsor commented Mar 27, 2012

This

$(function() {
});

is the same as

$(document).ready(function() {
});

So, all fine :)

There are no built in item loading related callbacks in 0.3. This has to be done in userland code. A simple loading would be:

$.get('/url/to/items.xml', function(data) {
    $(data).find('item').each(function() {
        // Create <li> element and append it to the list
    });
    // Reload (or create) carousel
    $('#carousel').jcarousel('reload');
}, 'xml');

@Dupond
Copy link
Author

Dupond commented Mar 27, 2012

OK, it works fine !

There is still a problem though : I'd like to load ONLY the images that are visible in the carousel. With the 0.2.8 version, the following code worked :

function carousel_comments_itemLoadCallback(carousel, state) {
    for (x=carousel.first-1;x<carousel.last;x++) {
        // the code to load the image
    }
}

How could I change "itemLoadCallback()", "carousel.first" and "carousel.last" ?

Furthermore, I was using "itemVisibleInCallback" and "carousel.size()" to add an "inactive" class to the external control links :

function carousel_editos_itemVisibleInCallback(carousel, item, idx, state) {
    if (carousel.first == 1) { $("#editos .jcarousel-prev").css("visibility", "hidden"); } else { $("#editos .jcarousel-prev").css("visibility", "visible"); }
    if (carousel.last == carousel.size()) { $("#editos .jcarousel-next").css("visibility", "hidden"); } else { $("#editos .jcarousel-next").css("visibility", "visible"); }
}

Which callback could I use instead of it ? How can I replace carousel.size() too ?

NB : it can be seen on this page.

Thanx for your help,
Best regards,
Dupond

@jsor
Copy link
Owner

jsor commented Mar 28, 2012

There is no itemLoadCallback. You have to do everything by yourself. I will add an example, but for now you're on your own ;)

There are some helper methods you can use for that:

carousel.first() returns the first visible item
carousel.first().index() returns the position (0-based)
carousel.last() returns the last visible item
carousel.last().index() returns the position (0-based)
carousel.visible()returns all visible items
carousel.list()returns all items
carousel.list().size() returns the number of items

@Dupond
Copy link
Author

Dupond commented Mar 28, 2012

I'm afraid I won't be able to do this on my own :( I understand there is no built-in callback. But I don't know how to replace them by myself.

So I think I'll wait for your example ;)

@charleskline
Copy link

I don't see this helper method of list() in 0.3 branch. Am I missing something?

var jc = $("#my-carousel").jcarousel();

jc.list();

TypeError: Object [object Object] has no method 'list'

@jsor
Copy link
Owner

jsor commented Mar 28, 2012

You have to call the method in the carousel object, not the jQuery object.

jc.jcarousel('list');

or

jc.data('jcarousel').list();

@Dupond
Copy link
Author

Dupond commented Mar 28, 2012

I think I could emulate the itemVisibleInCallback and itemLoadCallback, creating my own itemLoadCallback function with this code :

$(function() {
    $("#my-carousel").jcarousel().load(function() { itemLoadCallback(carousel); });
    $("#prev-link").click(function() { itemLoadCallback(carousel); });
    $("#next-link").click(function() { itemLoadCallback(carousel); });
});

function itemLoadCallback(carousel) {
    // my code goes here;
}

The aim is to have a function that would be triggered when the carousel loads for the first time, and, then, each time a new set of items is requested. Is it the right way to achieve this ?

@jsor
Copy link
Owner

jsor commented Mar 29, 2012

Nope, read the .load() docs.

@Dupond
Copy link
Author

Dupond commented Mar 29, 2012

OK, I'm far to be a pro... I guess I'll just wait for your example.

@Dupond
Copy link
Author

Dupond commented Mar 29, 2012

A few more questions please.

  1. Can you tell me where I will be able to find your example when it is ready ? Will it be there on Github ? Or did you mean on this thread ?
  2. I used to put the links to jquery.js and jcarousel.js at the end of my html file (just before </body>). But if I do this now, it simply doesn't work anymore. Do you know why ?
  3. I have an error in the console when I click on an external control link which is set like this :
$("#pager-button-prev a").click(function() { $("#carousel-comments").jcarousel("scroll", "-=1"); return false; });

Error : this._first is null
first = this._first.index();
jquery.jcarousel.js (line 580)

And so the external control link doesn't work.
4. Is it possible to scroll horizontally while displaying 3 items vertically in the carousel ? I used to have this code :

<ul>
    <li>
        <ul>
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </ul>
    </li>
    <li>
        <ul>
            <li>item 4</li>
            etc...
        </ul>
    </li>
</ul>

But since 0.3, it doesn't seem to work anymore (it's the 2nd carousel on the top right of this page, called "Nos prochaines animations"). It only displays one item at a time, instead of 3. Is it because of a change in the jCarousel code ? Or is it just a CSS problem ?

Thanx,
Best regards,
Dupond

@jsor
Copy link
Owner

jsor commented Apr 4, 2012

  1. I've added a loader plugin in the loader branch: https://github.com/jsor/jcarousel/tree/loader/plugins/loader

  2. No idea, theoretically it should work.

  3. Thats because you add the <ul></ul> after you initialize the carousel (in carousel_comments_init).

  4. If you have nested lists, you shluld use the listoption to only select the first level <ul>:

    $('#carousel').jcarousel({
        list: '>ul'
    });
    

@Dupond
Copy link
Author

Dupond commented Apr 4, 2012

Thanx for your plugin !

There is a mistake in your example code here : you have put a "," instead of a ";" in the following line : for (var i = first; i <= last, i++) {

The images are displayed thanx to your plugin, but it doesn't seem to work as expected : here is my code now :

img = new Array(Array);
$(function() {
    $("#carousel-comments-container").append('<div class="jcarousel" id="carousel-comments"><ul>\n</ul></div>');
    var loadCallback = function(first, last, type, ready) {
        $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
            var w = 0;
            $(data).find('image').each(function() {
                if (!img[w]) img[w] = new Array();
                img[w]['url'] = $(this).find('url').text();
                img[w]['src'] = $(this).find('src').text();
                img[w]['title'] = $(this).find('title').text();
                img[w]['width'] = $(this).find('width').text();
                img[w]['height'] = $(this).find('height').text();
                w++;
            });
            var items = $('#carousel-comments').jcarousel('items');
            for (var i = first; i <= last; i++) {
                items.eq(i).find('img').attr('src', img[i]['src']);
            };
            ready();
        }, 'xml');
    };
    var placeholderCallback = function(index) {
        return '<li><img src="../dotclear-files/themes/biblio/img/loading.gif"></li>';
    };
    $('#carousel-comments')
        .jcarousel()
        .jcarouselLoader({
            load: loadCallback,
            placeholder: placeholderCallback
        });
    $("#pager-button-prev a").click(function() { $("#carousel-comments").jcarousel("scroll", "-=3"); return false; });
    $("#pager-button-next a").click(function() { $("#carousel-comments").jcarousel("scroll", "+=3"); return false; });
});
  1. This code seems to load the xml file for all the items each time you scroll... Is there a way to load it only once ?

  2. The images are already loaded when scrolling to the next items... I had the following piece of code, so that the images are only displayed when they're loaded : should I include it somewhere ?

    $('#jcarousel-img-' + item)
    .hide()
    .one('load', function() { $(this).fadeIn(); })
    .attr('src', img[item]['src'])
    .each(function() { if (this.complete) $(this).trigger('load'); });

  3. The carousel never stops ! You can scroll to the next items again and again, even if there is no more images to load...

  4. Could we just disable the prev/next buttons when the carousel is at its first/last position ?

Thanx for your great help !

@jsor
Copy link
Owner

jsor commented Apr 4, 2012

Try this (not tested by me):

$(function() {
    var loadCallback = function(first, last, type, ready) {
        // Only load once on initialisation
        if (type !== 'init') {
            return;
        }

        var plugin   = this,
            carousel = this.carousel(),
            list     = carousel.list(),
            items    = carousel.items();

        $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
            // Set size
            plugin.option('size', parseInt($(data).find('total').text(), 10));

            // Add items
            $(data).find('image').each(function(index) {
                // Create the actual item
                var item = $('<li><a href="' + $(this).find('url').text() + '"><img src="' + $(this).find('src').text() + '"></a></li>');

                // Check if there is a placeholder item at this position
                var existing = items.eq(index);

                if (existing.size() > 0) {
                    // Replace placeholder
                    existing.replaceWith(item);
                } else {
                    // Append new item
                    list.append(item);
                }
            });

            ready();
        }, 'xml');
    };

    var placeholderCallback = function(index) {
        return '<li></li>';
    };

    var carouselComments = $('<div class="jcarousel" id="carousel-comments"><ul></ul></div>')
        .appendTo('#carousel-comments-container')
        .jcarousel()
        .jcarouselLoader({
            load: loadCallback,
            placeholder: placeholderCallback
        });

    $("#pager-button-prev a").click(function() { carouselComments.jcarousel("scroll", "-=1"); return false; });
    $("#pager-button-next a").click(function() { carouselComments.jcarousel("scroll", "+=1"); return false; });
});

@Dupond
Copy link
Author

Dupond commented Apr 4, 2012

Thanx again for your help.

  1. The "size" limit isn't set properly, it remains "10" instead of the "total" value indicated in my xml file...
  2. The images are still loaded before I scroll (they are displayed instantaneously, instead of loading a preload.gif animation).
  3. Only two images are scrolled, instead of 3 (my prev/next buttons are configured with "-=3" and "+=3" values)...

@jsor
Copy link
Owner

jsor commented Apr 4, 2012

  1. The option is set correctly. But i discovered a bug in the plugin which should probably also requires some changes in the jCarousel core. Will try to fix this asap.

  2. I havent't included this, you should apply the logic to the created item here:

    var item = $('<li><a href="' + $(this).find('url').text() + '"><img src="' + $(this).find('src').text() + '"></a></li>');
    
  3. Same as 1.

@Dupond
Copy link
Author

Dupond commented Apr 4, 2012

OK, I think I've got it, but I'm not sure : it behaves strangely, but maybe it's just because of the bug you talked about ?

My images still don't seem to be loaded only when scrolling though... It still seems that they're all loaded at once when the carousel loads for the first time... I've tried to "apply the logic" as you said :

var img = new Array(Array);
$(function() {
    var loadCallback = function(first, last, type, ready) {
        var plugin   = this,
            carousel = this.carousel();
        if (type !== 'init') { carousel_comments_itemLoad(carousel, first, last); return; }
        $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
            plugin.option('size', parseInt($(data).find('total').text(), 10));
            $(data).find('image').each(function(index) {
                if (!img[index]) img[index] = new Array();
                img[index]['url'] = $(this).find('url').text();
                img[index]['src'] = $(this).find('src').text();
                img[index]['title'] = $(this).find('title').text();
                img[index]['width'] = $(this).find('width').text();
                img[index]['height'] = $(this).find('height').text();
            });
            ready();
            carousel_comments_itemLoad(carousel, first, last);
        }, 'xml');
    };
    var placeholderCallback = function(index) { return '<li></li>'; };
    var carouselComments = $('<div class="jcarousel" id="carousel-comments"><ul>\n</ul></div>')
        .appendTo('#carousel-comments-container')
        .jcarousel()
        .jcarouselLoader({ load: loadCallback, placeholder: placeholderCallback });
    $("#pager-button-prev a").click(function() { $("#carousel-comments").jcarousel("scroll", "-=3"); return false; });
    $("#pager-button-next a").click(function() { $("#carousel-comments").jcarousel("scroll", "+=3"); return false; });
});

function carousel_comments_itemLoad(carousel, first, last) {
    var list  = carousel.list(),
        items = carousel.items();
    for (x=first; x<=last; x++) {
        var item = $('<li><a class="black-links" href="' + img[x]['url'] + '#comments" title="' + img[x]['title'] + '"><img src="../dotclear-files/themes/biblio/img/loading.gif" alt="' + img[x]['title'] + '" id="carousel-img-' + x + '" width="' + img[x]['width'] + 'px" height="' + img[x]['height'] + 'px" /></a></li>');
        var existing = items.eq(x);
        if (existing.size() > 0) { existing.replaceWith(item); } else { list.append(item); }
        $('#carousel-img-' + x)
            .hide()
            .one('load', function() { $(this).fadeIn(); })
            .attr('src', img[x]['src'])
            .each(function() { if (this.complete) $(this).trigger('load'); });
    }
}

@jsor
Copy link
Owner

jsor commented Apr 10, 2012

While writing the loader plugin, i realized that it not really adds some value, so i'm going to remove it ;)

Here's a reworked version of the code using a core event and including the fade in stuf of the images.

Note: The images are loaded all at once on initialization. Is there any reason why you don't want to do that?

$(function() {
    var loadCallback = function(event, carousel) {
        var list  = carousel.list();

        $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
            $(data).find('image').each(function(index) {
                // Create the actual item
                var item = $('<li><a class="black-links" href="' + $(this).find('url').text() + '#comments" title="' + $(this).find('title').text() + '"><img src="../dotclear-files/themes/biblio/img/loading.gif" width="' + $(this).find('width').text() + '" height="' + $(this).find('height').text() + '"></a></li>');

                list.append(item);

                item.find('img')
                    .hide()
                    .one('load', function() { $(this).fadeIn(); })
                    .attr('src', $(this).find('src').text())
                    .each(function() { if (this.complete) $(this).trigger('load'); });
            });

            carousel.reload();
        }, 'xml');
    };

    var carouselComments = $('<div class="jcarousel" id="carousel-comments"><ul></ul></div>')
        .appendTo('#carousel-comments-container')
        .bind('jcarouselinit', loadCallback)
        .jcarousel();

    $("#pager-button-prev a").click(function() { carouselComments.jcarousel("scroll", "-=1"); return false; });
    $("#pager-button-next a").click(function() { carouselComments.jcarousel("scroll", "+=1"); return false; });
});

@Dupond
Copy link
Author

Dupond commented Apr 10, 2012

It's because if you have 100 images, loaded all at once on initialization, it'll be veeeeery long to load ;) So what would be nice is to load the xml code from the PHP file once and for all on initialization, and then only load the images themselves when they need to be displayed...

@Dupond
Copy link
Author

Dupond commented Apr 14, 2012

Furthermore, if the user doesn't scroll, you'll have loaded 97 images for nothing...

I'm a bit baffled here : is it just not possible with the 0.3 branch ? You had done it yourself quite easily in your own example for 0.2.8, using itemLoadCallback (and it worked quite well) : so we would just need an equivalent to this in the 0.3 branch.

@jsor
Copy link
Owner

jsor commented Apr 21, 2012

The item loading stuff in 0.2 is flawed. It worked well only in few cases.

If you want to load the images only if the become visible, just do this

    $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
        $(data).find('image').each(function(index) {
            // Create the actual item
            var item = $('<li><a class="black-links" href="' + $(this).find('url').text() + '#comments" title="' + $(this).find('title').text() + '"><img data-src="' + $(this).find('src').text() + ' src="../dotclear-files/themes/biblio/img/loading.gif" width="' + $(this).find('width').text() + '" height="' + $(this).find('height').text() + '"></a></li>');

            list.append(item);

            item.bind('jcarouselitemvisiblein' function() {
                var img = $(this).find('img'),
                    src = img.data('src');

                if (!src) {
                    return;
                }

                img
                    .hide()
                    .one('load', function() { $(this).fadeIn(); })
                    .attr('src', src)
                    .each(function() { if (this.complete) $(this).trigger('load'); });
            });
        });

        carousel.reload();
    }, 'xml');

We simply bind on the jcarouselitemvisiblein event and if it's triggered, we exchange the src attribute to the real image url stored in the data-src attribute

@Dupond
Copy link
Author

Dupond commented Apr 21, 2012

Thank you soooo much for your great help ! (back from holidays maybe ? ;)

I'm not sure the method is yet perfect though (you'll clearly see the problem if you browse without CSS) : with this code (which works just fine, as we can see on the page where I use it), all the images are added at once, but only 3 are indeed visible. So if you browse with a screen reader for example (for people with disabilities etc.), you have useless elements displayed (that is to say : you have a list of loading gifs !)...
So it would be better to load the PHP file, and, then, to only add to the DOM the images that are visible, don't you think so ? Is it possible to achieve this ?

Furthermore, the width and height attributes of the images should be added only after the images are loaded (because the loading gif is displayed much bigger than it should).

By the way, one of my carousel (still on my page, it's the one called "Nos prochaines animations") simply doesn't work with 0.3 : you had advised me (12th comment of this post) to add $("#carousel-lastevents").jcarousel({animation: 0, list: '>ul'}); so that's what I've done : the items are displayed, but the scroll doesn't work (the "next" button has no effect indeed).

Any idea anyone ? Thanx !

@jsor
Copy link
Owner

jsor commented Apr 23, 2012

Updated code which only adds required items (without loader plugin), untested as usual ;):

$(function() {
    var carouselCommentsNumItems = 3, // 3 items visible
        carouselCommentsData = [];

    var createItem = function(data) {
        var item = $('<li><a class="black-links" href="' + data.url + '#comments" title="' + data.title + '"><img data-src="' + data.src + ' src="../dotclear-files/themes/biblio/img/loading.gif"></a></li>');

        var img = item.find('img');

        img
            .hide()
            .one('load', function() { $(this).attr('width', data.width).attr('height', data.height).fadeIn(); })
            .attr('src', src)
            .each(function() { if (this.complete) $(this).trigger('load'); });
    };

    var initCallback = function(event, carousel) {
        var list  = carousel.list();
        $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
            // Store data
            $(data).find('image').each(function(index) {
                var item = {
                    'url': $(this).find('url').text(),
                    'title': $(this).find('title').text(),
                    'src': $(this).find('src').text(),
                    'width': $(this).find('width').text(),
                    'height': $(this).find('height').text()
                };

                carouselCommentsData.push(item);
            });

            // Create first set of items
            var list  = carousel.list(),
                size = carouselCommentsData.length;

            for (var i = 0, i < carouselCommentsNumItems; i++) {
                if (i >= size) {
                    break;
                }

                list.append(createItem(carouselCommentsData[i]));
            }

            carousel.reload();
        }, 'xml');
    };

    var scrollCallback = function(event, carousel, target) {
        var list  = carousel.list(),
            items = carousel.items(),
            size = carouselCommentsData.length,
            parsed = jCarousel.parseTarget(target),
            index = parsed.target;

        // Only relative (prev/next buttons)
        if (!parsed.relative) {
            return;
        }

        // Out of range
        if (index >= size) {
            return;
        }

        // Already added
        if (items.eq(index).size() > 0) {
            return;
        }

        for (var i = index, i < carouselCommentsNumItems; i++) {
            if (i >= size) {
                break;
            }

            list.append(createItem(carouselCommentsData[i]));
        }

        carousel.reload();
    };

    var carouselComments = $('<div class="jcarousel" id="carousel-comments"><ul></ul></div>')
        .appendTo('#carousel-comments-container')
        .bind('jcarouselinit', initCallback)
        .bind('jcarouselscroll', scrollCallback)
        .jcarousel();

    $("#pager-button-prev a").click(function() { carouselComments.jcarousel("scroll", "-=1"); return false; });
    $("#pager-button-next a").click(function() { carouselComments.jcarousel("scroll", "+=1"); return false; });
});

Regarding the not-working carousel, try:

$("#carousel-lastevents").jcarousel({animation: 0, list: '>ul', items: '>li});

@Dupond
Copy link
Author

Dupond commented Apr 23, 2012

Wow ! Thanx a lot ! But unfortunately it doesn't seem to work : I've changed a few typos ("," instead of ";" in the "for" loop, for example, or "src" instead of "data.src" on line 13), and I've put it online : but, as you can see, it does nothing. The images are not displayed (in fact, the items are not added to the DOM, as we can see in the generated source code).

Here is the final code I used :

$(function() {
    $("#carousel-comments-container").prepend('\n<span id="pager-button-prev"><a class="black-links" href="#" title="Documents pr&eacute;c&eacute;dents">&lt;</a></span>\n<span id="pager-button-next"><a class="black-links" href="#" title="Documents suivants">&gt;</a></span>');
    var carouselCommentsNumItems = 3, // 3 items visible
        carouselCommentsData = [];

    var createItem = function(data) {
        var item = $('<li><a class="black-links" href="' + data.url + '#comments" title="' + data.title + '"><img data-src="' + data.src + '" src="../dotclear-files/themes/biblio/img/loading.gif"></a></li>');

        var img = item.find('img');

        img
            .hide()
            .one('load', function() { $(this).attr('width', data.width).attr('height', data.height).fadeIn(); })
            .attr('src', data.src)
            .each(function() { if (this.complete) $(this).trigger('load'); });
    };

    var initCallback = function(event, carousel) {
        var list  = carousel.list();
        $.get('../dotclear-files/themes/biblio/js/dynamic_ajax_php.php', function(data) {
            // Store data
            $(data).find('image').each(function(index) {
                var item = {
                    'url': $(this).find('url').text(),
                    'title': $(this).find('title').text(),
                    'src': $(this).find('src').text(),
                    'width': $(this).find('width').text(),
                    'height': $(this).find('height').text()
                };

                carouselCommentsData.push(item);
            });

            // Create first set of items
            var list  = carousel.list(),
                size = carouselCommentsData.length;

            for (var i = 0; i < carouselCommentsNumItems; i++) {
                if (i >= size) {
                    break;
                }

                list.append(createItem(carouselCommentsData[i]));
            }

            carousel.reload();
        }, 'xml');
    };

    var scrollCallback = function(event, carousel, target) {
        var list  = carousel.list(),
            items = carousel.items(),
            size = carouselCommentsData.length,
            parsed = jCarousel.parseTarget(target),
            index = parsed.target;

        // Only relative (prev/next buttons)
        if (!parsed.relative) {
            return;
        }

        // Out of range
        if (index >= size) {
            return;
        }

        // Already added
        if (items.eq(index).size() > 0) {
            return;
        }

        for (var i = index; i < carouselCommentsNumItems; i++) {
            if (i >= size) {
                break;
            }

            list.append(createItem(carouselCommentsData[i]));
        }

        carousel.reload();
    };

    var carouselComments = $('<div class="jcarousel" id="carousel-comments"><ul></ul></div>')
        .appendTo('#carousel-comments-container')
        .bind('jcarouselinit', initCallback)
        .bind('jcarouselscroll', scrollCallback)
        .jcarousel();
    $("#pager-button-prev a").bind('jcarouselcontrolinactive', function() { $("#pager-button-prev").css("visibility", "hidden"); }).bind('jcarouselcontrolactive', function() { $("#pager-button-prev").css("visibility", "visible"); }).jcarouselControl({ target: '-=3' });
    $("#pager-button-next a").bind('jcarouselcontrolinactive', function() { $("#pager-button-next").css("visibility", "hidden"); }).bind('jcarouselcontrolactive', function() { $("#pager-button-next").css("visibility", "visible"); }).jcarouselControl({ target: '+=3' });
});

(However, regarding the previously not-working carousel, now it works ! Thanx a lot !)

@jsor
Copy link
Owner

jsor commented Apr 23, 2012

The createItem function misses the return statement ;-)

var createItem = function(data) {
    var item = $('<li><a class="black-links" href="' + data.url + '#comments" title="' + data.title + '"><img data-src="' + data.src + '" src="../dotclear-files/themes/biblio/img/loading.gif"></a></li>');

    var img = item.find('img');

    img
        .hide()
        .one('load', function() { $(this).attr('width', data.width).attr('height', data.height).fadeIn(); })
        .attr('src', data.src)
        .each(function() { if (this.complete) $(this).trigger('load'); });

    return item;
};

@Dupond
Copy link
Author

Dupond commented Apr 24, 2012

OK, the items are added now... but there is no more prev/next scroll button added ;)

Should I change a particular variable ?
Thanx very much for all your help ;)

@jsor
Copy link
Owner

jsor commented Apr 26, 2012

Now, that we load the items dynamically, the prev/next buttons don't know that there are more items available than actually items in the carousel.

I've just pushed to the master branch. Take jquery.jcarousel.js from there and change the following section:

var carouselComments = $('<div class="jcarousel" id="carousel-comments"><ul></ul></div>')
    .appendTo('#carousel-comments-container')
    .bind('jcarouselinit', initCallback)
    .bind('jcarouselscroll', scrollCallback)
    .bind('jcarouselhasnext', function(event, carousel) {
        if (carousel.last().index() < carouselCommentsData.length) {
            event.preventDefault();
        }
    })
    .jcarousel();

The new part is the binding to the jcarouselhasnextevent.

@Dupond
Copy link
Author

Dupond commented Apr 26, 2012

Thanx very much ! Unfortunately, it doesn't seem to work : as you can see, there is still no prev/next scroll button displayed... Maybe I've done something wrong ?

@jsor
Copy link
Owner

jsor commented Apr 26, 2012

You must use the latest version of jquery.jcarousel.js: https://github.com/jsor/jcarousel/blob/master/src/jquery.jcarousel.js

@Dupond
Copy link
Author

Dupond commented Apr 26, 2012

Yes, that's what I've done. Just to be sure, I just come to do it again : same result. (I click on the link you gave, and then I copy/paste the code to my jquery.jcarousel.js file, since I don't find how to download it)...

@jsor
Copy link
Owner

jsor commented Apr 26, 2012

I checked the file /dotclear-files/themes/biblioTest/js/min/jquery.jcarousel.js and it doesn't have the latest changes in it (b1e0f6f).

@Dupond
Copy link
Author

Dupond commented Apr 27, 2012

Grrr... Sorry for this : I had changed the wrong file.

Now it's better (the "next" scroll button is displayed) but not yet perfect : the next scroll button has no effect (that is to say : when you click on it, nothing happens... it just doesn't scroll)...

Thanx very much for all the help you give to me !

@jsor
Copy link
Owner

jsor commented Apr 27, 2012

We have a javascript error: carousel.last() is null. Change the new callback to:

.bind('jcarouselhasnext', function(event, carousel) {
    var last = carousel.last();
    if (last && last.index() < carouselCommentsData.length) {
        event.preventDefault();
    }
})

@Dupond
Copy link
Author

Dupond commented Apr 27, 2012

Done... but, unfortunately, same behaviour : the scroll button still doesn't seem to work...

@jsor
Copy link
Owner

jsor commented Apr 27, 2012

Small bug. Replace:

for (var i = index; i < carouselCommentsNumItems; i++) {

with

for (var i = index; i < i + carouselCommentsNumItems; i++) {

@Dupond
Copy link
Author

Dupond commented Apr 27, 2012

Thanx ! Now it works just fine ! The "next" scroll buttons never "disappear" though (I'm using the "control" plugin, and it never becomes inactive). This is strange, since the "prev" button works just fine...

Anyway, thank you very much for all the time you gave to this project, since I'd never have been able to do this on my own !

Here are a few more things I noticed :

  1. Is the data-src=etc. attribute of the image still needed ? I was under the impression that it wasn't useful anymore.
  2. Isn't the "list" variable declared twice in the initCallback function (where we can find two var list = carousel.list()) ?
  3. Sorry if this seems obvious for you : is there any advantage to write var list=carousel.list(); list.append(etc.) (2 lines of code) instead of carousel.list().append(etc...) (only 1 line of code) ?
  4. Since an image is already an inline-element, why is there a style="display: inline;" attribute added to the images ?
  5. Wouldn't it make sense to add a callback to jCarousel which would be triggered at initialization of the carousel AND at scrolling (that is to say, each time a new set of items is requested) ? That way, you wouldn't have to write redundant code (the for (var i=etc...) loop, for example). Furthermore, creating a counter would be much easier : something like $("#editos .counter").text("").prepend(carousel.first().index() + " / " + carousel.list().size()); that we could put in the correct callback ;)

@jsor
Copy link
Owner

jsor commented Apr 27, 2012

Fix for the next button:

Replace

if (last && last.index() < carouselCommentsData.length) {

with

if (last && last.index() < (carouselCommentsData.length - 1)) {

Question 1- 4: Yep, i just wrote that code out of my head. There is probably room for improvement ;-)
Question 5: You can bind to 2 events at once: $().bind('jcarouselinit,jcarouselscroll', function() {});

@Dupond
Copy link
Author

Dupond commented Apr 27, 2012

Mmmm... Not sure the "-1" should be added there, since when you scroll for the first time, 4 items are added at once (instead of three : cf. var carouselCommentsNumItems = 3, // 3 items visible).

As for the addition of style="display: inline;" on the images, it seems to be added by jCarousel itself, since it doesn't appear in the js config file...

@jsor
Copy link
Owner

jsor commented Apr 27, 2012

The scrollCallback is buggy, replace with

var scrollCallback = function(event, carousel, target) {
    var list  = carousel.list(),
        items = carousel.items(),
        size = carouselCommentsData.length,
        parsed = jCarousel.parseTarget(target),
        first = carousel.last().index() + 1,
        last = first + parsed.target;

    for (var i = first; i < last; i++) {
        if (i >= size) { break; }
        list.append(createItem(carouselCommentsData[i]));
    }
    carousel.reload();
};

Don't know why style="display: inline;"is added, definitely not from jCarousel. Probably it is added by jQuery from .hide()/.fadeIn().

@Dupond
Copy link
Author

Dupond commented Apr 27, 2012

It works... only the first time you scroll : scroll ("next" button) twice (until the end of the carousel, in fact), then scroll back ("prev" button once or twice, it doesn't matter), and then scroll again ("next" button again) : the four last items are added several times (each time you scroll back and forth, they're added again)...

@jsor
Copy link
Owner

jsor commented Apr 27, 2012

Ah, yes. forgt to add the check if the item already exists:

var scrollCallback = function(event, carousel, target) {
    var list  = carousel.list(),
        items = carousel.items(),
        size = carouselCommentsData.length,
        parsed = jCarousel.parseTarget(target),
        first = carousel.last().index() + 1,
        last = first + parsed.target;

    for (var i = first; i < last; i++) {
        if (i >= size) { break; }
        if (items.eq(i).size() > 0) { continue; }
        list.append(createItem(carouselCommentsData[i]));
    }
    carousel.reload();
};

@Dupond
Copy link
Author

Dupond commented Apr 27, 2012

Aaaahhh ! Now it really works like a charm :)

I'm very grateful to you of all the time you gave to me. Thanx very much for this.

One other thing : when I disable javaScript and reload the page, only the current item is displayed in the carousels of my page. Of course, I'm no more talking about a carousel with dynamic content loading : I'm talking about a "normal" carousel, with for example 3 items in it, scrolled 1 by 1. If I disable jS, only 1 item (the current one) will be visible. So, from an accessibility point of view, there's a loss of informations : all the items of the carousels should be displayed (with a vertical or horizontal scrolling bar, for example). Is it a CSS problem ? Please note that I don't want you to do the job for me (in fact... you have ever done all the job for me ;)). I'd just like to know if, with the current 0.3 branch, we can have this sort of behaviour (I'm a bit better in CSS than in jS, so if this is just a CSS problem, I assume I can solve this by myself).

PS : the following code has no effect for the moment : $("#carousel-editos").bind('jcarouselinit,jcarouselscroll', function(event, carousel) { $("#editos .counter").text("").prepend(carousel.first().index() + " / " + carousel.list().size()); }).jcarousel({animation: 0}); It doesn't display the counter. Would anyone have an idea ?

@jsor
Copy link
Owner

jsor commented May 2, 2012

Yep, its up to you how style it. Since jCarousel adds the class jcarousel you can do something like this for example:

.mycarousel {
    overflow: auto;
}

.mycarousel.jcarousel {
    overflow: hidden;
}

Regarding the counter. My mistake, multiple events must be separated by a space:

.bind('jcarouselinitend jcarouselscrollend', function(event, carousel) { 
    $("#editos .counter").text("").prepend((carousel.first().index() +  1)+ " / " + carousel.items().size()); 
})

I made a few corrections:

  1. Bind to the *end events
  2. Do index() + 1 because indexes are 0-based
  3. Use carousel.items().size()instead of carousel.list().size()

@Dupond
Copy link
Author

Dupond commented May 4, 2012

Wow ! Thanx very much : it works fine !

So the only trouble left I can see is the annoying keyboard browsing issue. I've seen your "focus" example, but adding the following code to my carousel has no effect :

.focus(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $(this).closest('.jcarousel').jcarousel('scroll', this);
});

Here is what it does when tabbing throughout the page using the keyboard :

  1. The focus goes to the first link inside of the first item of the carousel, even if it's not the first displayed item...
  2. When you keep browsing using the "tab" key, the focus goes to elements after the last displayed item...

The focus should go to the first link inside of the first displayed item, and, after the last link in the last displayed item, the focus should go out of the carousel.

Is it something which could be done via a plugin ? Or is it something that can already be done using the actual 0.3 code ? Something to settle up inside of the configuration javaScript file maybe ?

Thanx for your help... once more,
Best regards,
Dupond

@jsor
Copy link
Owner

jsor commented May 4, 2012

If you want to use it like i did in the example, you have to set the tabindex attribute explicitly on each element.

@Dupond
Copy link
Author

Dupond commented May 4, 2012

I can't do that, since I'd have to set the tabindex attribute to each link of my page, right ? But some parts of the page are shared with other pages of the blog, so this is just not possible for me.

Is there a way to use the "focus" callback in order to achieve this ? (I mean : the focus goes to the first link of the first displayed item, and then goes out after the last link of the last displayed item ?)

Also, I was wondering if jCarousel could be used to create a "more" link, so that more content is added (instead of "scrolled") at the end of a page : it's exactly the same as the carousel with dynamic content loading that you made for me, but without the "scrolling" function (the new content loaded is added at the end of the container, instead of replacing the old one). If possible, I'd like to stay with jCarousel, instead of adding another plugin again... but is this possible ?

Thanx,
Best regards,
Dupond

@jsor
Copy link
Owner

jsor commented May 5, 2012

Regarding the focus stuff, i don't know actually. Maybe better ask on SO or something. Second question: Use the right tool for the job, jCarousel is not made for something like this.

@Dupond
Copy link
Author

Dupond commented May 6, 2012

OK, I'll see what I can't do for the keyboard browsing issue. I had solved it with the old 0.2.8 version (it can be seen here), but it's been a reaaally hard work for me... and I've been unable to upgrade it so that it can be used with the 0.3 branch :(

Now I think it's time to close this looong post ;)

Thanx again for all the great help you gave to me !

@Dupond Dupond closed this as completed May 6, 2012
@Dupond
Copy link
Author

Dupond commented May 7, 2012

Just in case, I've asked the question about the keyboard browsing problem on SO.

@Dupond
Copy link
Author

Dupond commented May 10, 2012

Unfortunately, I had no answer on SO. And no more luck on the jQuery forums...

... It's a great shame, since this is an important accessibility issue...

@jsor
Copy link
Owner

jsor commented May 10, 2012

I'm still not sure what exactly the problem is. The topic has nothing to do with jCarousel, not event with JavaScript. If you solved it with your 0.2.8 version, you should be able to solve it for 0.3 as well.

@Dupond
Copy link
Author

Dupond commented May 16, 2012

After all it was not that difficult to fix this issue :)

Here's what I've done :

// The focus must go to the first link of the first VISIBLE item :
$("#carousel-comments").delegate("li:first a", "focusin", function () {
    $("#carousel-comments li.jcarousel-item-first a").focus();
    return false;
});
// After the last link of the last visible item, the focus should go out :
$("#carousel-comments").delegate("li.jcarousel-item-last a", "keydown", function (e) {
    var code = (e.keyCode ? e.keyCode : e.which);
    if (code == 9) { $("#rang3 a").first().focus(); return false; }
});

@marya-ivanovna
Copy link

Hello! Everything work's perfectly, but some problem in scrollCallback from this code:

var scrollCallback = function(event, carousel, target) {
    var list  = carousel.list(),
        items = carousel.items(),
        size = carouselCommentsData.length,
        parsed = jCarousel.parseTarget(target),
        first = carousel.last().index() + 1,
        last = first + parsed.target;
    for (var i = first; i < last; i++) {
        if (i >= size) { break; }
        if (items.eq(i).size() > 0) { continue; }
        list.append(createItem(carouselCommentsData[i]));
    }
    carousel.reload();
};

Error from firebug console:

ReferenceError: jCarousel is not defined
parsed = jCarousel.parseTarget(target);

@jsor
Copy link
Owner

jsor commented Jan 10, 2013

In the meantime, everything was moved under the $namespace, so it is now

$.jCarousel.parseTarget(target)

@marya-ivanovna
Copy link

Works like a charm! Many thx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants