Modify InfiniteScroll to work horizontally
Asked Answered
E

1

11

I see a few posts on this topic here but couldnt quite find one that actually solves the issue im trying to handle.

On my site i have pages of blog posts. i have setup infiniteScroll (https://github.com/paulirish/infinite-scroll) and it is working properly to load in the next page of content triggered by the scrolling action. i have set my div to scroll horizontally but i cannot figure out how to modify the infiniteScroll script (and the local.js script) to be triggered by a horizontal scroll rather than a vertical scroll.

here is the progress: https://adrtimesv6.squarespace.com/library/ (you have to type in the visitor access captcha to view while im building).

Any help would be greatly appreciated!! i have been tinkering and hunting through the interwebs for days now trying to get this to work....

My html structure is like so:

<div class="listWrapper">
    <div id="scroller">
        <article class="item"></article>
        <article class="item"></article>
        ... and so on
    </div>
</div>

My script looks like this:

$('#scroller').infinitescroll({
    behavior: 'local',
    binder: $('#scroller'),
    nextSelector: ".pagination .nextPage",
    navSelector: ".pagination",
    itemSelector: ".item",
    animate: false,
    extraScrollPx: 0,
    bufferPx: 235,
    pixelsFromNavToRight: undefined,
});

And i have modified the infiniteScroll js file to change all height references to width, top to left, and bottom to right:

;
(function ($) {
    $.fn.infinitescroll = function (options, callback) {
        function debug() {
            if (opts.debug) {
                window.console && console.log.call(console, arguments)
            }
        }

        function areSelectorsValid(opts) {
            for (var key in opts) {
                if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) {
                    debug('Your ' + key + ' found no elements.');
                    return false;
                }
                return true;
            }
        }

        function determinePath(path) {
            path.match(relurl) ? path.match(relurl)[2] : path;
            if (path.match(/^(.*?)\b2\b(.*?$)/)) {
                path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
            } else
            if (path.match(/^(.*?)2(.*?$)/)) {
                if (path.match(/^(.*?page=)2(\/.*|$)/)) {
                    path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1);
                    return path;
                }
                debug('Trying backup next selector parse technique. Treacherous waters here, matey.');
                path = path.match(/^(.*?)2(.*?$)/).slice(1);
            } else {
                if (path.match(/^(.*?page=)1(\/.*|$)/)) {
                    path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1);
                    return path;
                }
                debug('Sorry, we couldn\'t parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.');
                props.isInvalidPage = true;
            }
            return path;
        }

        function getDocumentWidth() {
            return opts.localMode ? ($(props.container)[0].scrollWidth && $(props.container)[0].scrollWidth) : $(document).width()
        }

        function isNearRight() {
            var pixelsFromWindowRightToRight = 0 +
                getDocumentWidth() - (opts.localMode ? $(props.container).scrollLeft() : ($(props.container).scrollLeft() || $(props.container.ownerDocument.body).scrollLeft())) - $(opts.localMode ? props.container : window).width();
            debug('math:', pixelsFromWindowRightToRight, props.pixelsFromNavToRight);
            return (pixelsFromWindowRightToRight - opts.bufferPx < props.pixelsFromNavToRight);
        }

        function showDoneMsg() {
            props.loadingMsg.find('img').hide().parent().find('div').html(opts.donetext).animate({
                opacity: 1
            }, 2000).fadeOut('normal');
            opts.errorCallback();
        }

        function infscrSetup() {
            if (props.isDuringAjax || props.isInvalidPage || props.isDone) return;
            if (!isNearRight(opts, props)) return;
            $(document).trigger('retrieve.infscr');
        }

        function kickOffAjax() {
            props.isDuringAjax = true;
            props.loadingMsg.appendTo(opts.contentSelector).show();
            $(opts.navSelector).hide();
            props.currPage++;
            debug('heading into ajax', path);
            box = $(opts.contentSelector).is('table') ? $('<tbody/>') : $('<div/>');
            frag = document.createDocumentFragment();
            box.load(path.join(props.currPage) + ' ' + opts.itemSelector, null, loadCallback);
        }

        function loadCallback() {
            if (props.isDone) {
                showDoneMsg();
                return false;
            } else {
                var children = box.children().get();
                if (children.length == 0) {
                    return $.event.trigger("ajaxError", [{
                        status: 404
                    }]);
                }
                while (box[0].firstChild) {
                    frag.appendChild(box[0].firstChild);
                }
                $(opts.contentSelector)[0].appendChild(frag);
                props.loadingMsg.fadeOut('normal');
                if (opts.animate) {
                    var scrollTo = $(".listWrapper").scrollLeft() + $('#infscr-loading').width() + opts.extraScrollPx + 'px';
                    $(".listWrapper").animate({
                        scrollLeft: scrollTo
                    }, 800, function () {
                        props.isDuringAjax = false;
                    });
                }
                callback.call($(opts.contentSelector)[0], children);
                if (!opts.animate) props.isDuringAjax = false;
            }
        }
        $.browser.ie6 = $.browser.msie && $.browser.version < 7;
        var opts = $.extend({}, $.infinitescroll.defaults, options),
            props = $.infinitescroll,
            box, frag;
        callback = callback || function () {};
        if (!areSelectorsValid(opts)) {
            return false;
        }
        props.container = opts.localMode ? this : document.documentElement;
        opts.contentSelector = opts.contentSelector || this;
        var relurl = /(.*?\/\/).*?(\/.*)/,
            path = $(opts.nextSelector).attr('href');
        if (!path) {
            debug('Navigation selector not found');
            return;
        }
        path = determinePath(path);
        if (opts.localMode) $(props.container)[0].scrollLeft = 0;
        props.pixelsFromNavToRight = getDocumentWidth() +
            (props.container == document.documentElement ? 0 : $(props.container).offset().left) -
            $(opts.navSelector).offset().left;
        props.loadingMsg = $('<div id="infscr-loading" style="text-align: center;"><img alt="Loading" src="' +
            opts.loadingImg + '" /><div>' + opts.loadingText + '</div></div>');
        (new Image()).src = opts.loadingImg;
        $(document).ajaxError(function (e, xhr, opt) {
            debug('Page not found. Self-destructing...');
            if (xhr.status == 404) {
                showDoneMsg();
                props.isDone = true;
                $(opts.localMode ? this : window).unbind('scroll.infscr');
            }
        });
        $(opts.localMode ? this : window).bind('scroll.infscr', infscrSetup).trigger('scroll.infscr');
        $(document).bind('retrieve.infscr', kickOffAjax);
        return this;
    }
    $.infinitescroll = {
        defaults: {
            debug: false,
            preload: false,
            nextSelector: "div.navigation a:first",
            loadingImg: "http://www.infinite-scroll.com/loading.gif",
            loadingText: "<em>Loading</em>",
            donetext: "<em>Congratulations, you've reached the end.</em>",
            navSelector: "div.navigation",
            contentSelector: null,
            extraScrollPx: 150,
            itemSelector: "div.post",
            animate: false,
            localMode: false,
            bufferPx: 40,
            errorCallback: function () {}
        },
        loadingImg: undefined,
        loadingMsg: undefined,
        container: undefined,
        currPage: 1,
        currDOMChunk: null,
        isDuringAjax: false,
        isInvalidPage: false,
        isDone: false
    };
})(jQuery);

I also switched out all the top, left, right, bottom references in the local.js file:

// Calculate internal width (used for local horizontal scroll)
function infsrc_local_hiddenWidth(element) {
   var width = 0;
   jQuery(element).children().each(function() {
     width = width + jQuery(this).outerWidth(false);
   });
   return width;
}

jQuery.extend(jQuery.infinitescroll.prototype,{
   _nearright_local: function infscr_nearright_local() {
       var opts = this.options, instance = this,
           pixelsFromWindowRightToRight = infsrc_local_hiddenWidth(opts.binder)
               - jQuery(opts.binder).scrollLeft() - jQuery(opts.binder).width();

       if (opts.local_pixelsFromNavToRight == undefined){
           opts.local_pixelsFromNavToRight = infsrc_local_hiddenWidth(opts.binder) +
         jQuery(opts.binder).offset().left - jQuery(opts.navSelector).offset().left;
       }
       instance._debug('local math:', pixelsFromWindowRightToRight,
opts.local_pixelsFromNavToRight);

       return (pixelsFromWindowRightToRight - opts.bufferPx < opts.local_pixelsFromNavToRight);
   }
});

UPDATE ** It seems as though it is almost all working correctly, there are a couple little glitches left: -- the content is loaded and the element the content is loaded into is scrolling horizontally, however the load seems to still be triggered by the vertical scroll and not the horizontal scroll like i need it. -- it seems like the local.js file is not being triggered. if i remove the script then nothing changes. this might be the heart of my problem?

Eisk answered 16/7, 2013 at 22:12 Comment(10)
Hmmmm - so i've fiddled around with it some more and it seems to be working a little better now in safari and chrome but not in firefox. in chrome and safari the load/scroll seems to trigger on both horizontal and vertical scrolling (i need it to only be horizontally triggered) and in firefox it is still vertical only.Eisk
it seems as though i was able to get the scrolling element's width to update properly now.Eisk
hmmm perhaps it only seems like its getting the load/scroll triggered by scrolling horizontally in chrome and safari because those browsers somehow trigger the down scroll when pulling the page to the left?Eisk
.... wondering if what im trying to do is possible? .... seems like it should be~Eisk
Maybe if you try to capture the vertical scroll event and trigger the load in the callback.Methylene
see these links(there are 3) https://mcmap.net/q/1159974/-horizontal-infinite-scroll ; #6398574 ; github.com/paulirish/infinite-scroll/issues/151Superhighway
Thanks guys! i had been through all those posts before posting :(Eisk
looks like the "local mode" that is supposed to apply the script to a containing element instead of the window is not being triggered. if i remove that script nothing changes :(Eisk
Did you make it work? This is very old, should I try to help you or did you find the solution?Semite
check your css buddy, isn't article with width:100% or anything greater than 50, check with firebugWidera
M
1

Is this what you're looking for?

var scrollp = Math.ceil( $('body').width() / 20 );
$('body').mousewheel(function(event, delta) {
    if (delta < 0) {
        $('body').scrollTo('+='+scrollp, 50, {easing:'easeInOutSine', queue:false, axis:'x'});
    } else {
        $('body').scrollTo('-='+scrollp , 50, {easing:'easeInOutSine', queue:false, axis:'x'} );
        event.preventDefault();
    }
});

http://jsfiddle.net/jonnysooter/RHKyP/18/

EDIT

If this sort of "jump back to the start" isn't what you want, then just modify the code a bit to start loading your content in this callback if the scroll hits the full width. When your content loads, the div width will increase and with it the scroll.

This question might shed some light on another approach. horizontal infinite scroll

Methylene answered 26/7, 2013 at 14:28 Comment(3)
I'm hoping to figure out i should edit the source of the jquery plugin i am already using - the edit i need is to change the part that triggers the load to happen on the horizontal scroll instead of the vertical scroll. also, the scroll is applied to an element and not the page body. all other functions are working properly.Eisk
I'm still a beginner with jquery so im trying to understand the code im using (the InfiniteScroll from Paul Irish) and understand why it is not working, rather than find and implement a new solution. Thanks so much for your help! if i cant get what im using to work i will give this a try :)Eisk
Hi Jonny, thanks for your suggestion, i took a closer look at your at it but it doesnt seem to relate very well with my issue.Eisk

© 2022 - 2024 — McMap. All rights reserved.