dist/famous-flex.js
function ListLayout(context, options) {

        // Local data
        var size = context.size;
        var direction = context.direction;
        var alignment = context.alignment;
        var revDirection = direction ? 0 : 1;
        var offset;
        var margins = LayoutUtility.normalizeMargins(options.margins);
        var spacing = options.spacing || 0;
        var node;
        var nodeSize;
        var itemSize;
        var getItemSize;
        var lastSectionBeforeVisibleCell;
        var lastSectionBeforeVisibleCellOffset;
        var lastSectionBeforeVisibleCellLength;
        var lastSectionBeforeVisibleCellScrollLength;
        var lastSectionBeforeVisibleCellTopReached;
        var firstVisibleCell;
        var lastNode;
        var lastCellOffsetInFirstVisibleSection;
        var isSectionCallback = options.isSectionCallback;
        var bound;

        //
        // Sanity checks
        //
        if (spacing && typeof spacing !== 'number') {
            console.log('Famous-flex warning: ListLayout was initialized with a non-numeric spacing option. ' + // eslint-disable-line no-console
                'The CollectionLayout supports an array spacing argument, but the ListLayout does not.');
        }

        //
        // Reset size & translation
        //
        set.size[0] = size[0];
        set.size[1] = size[1];
        set.size[revDirection] -= (margins[1 - revDirection] + margins[3 - revDirection]);
        set.translate[0] = 0;
        set.translate[1] = 0;
        set.translate[2] = 0;
        set.translate[revDirection] = margins[direction ? 3 : 0];

        //
        // Determine item-size or use true=size
        //
        if ((options.itemSize === true) || !options.hasOwnProperty('itemSize')) {
            itemSize = true;
        }
        else if (options.itemSize instanceof Function) {
            getItemSize = options.itemSize;
        }
        else {
            itemSize = (options.itemSize === undefined) ? size[direction] : options.itemSize;
        }

        //
        // Determine leading/trailing margins
        //
        margin[0] = margins[direction ? 0 : 3];
        margin[1] = -margins[direction ? 2 : 1];

        //
        // Process all next nodes
        //
        offset = context.scrollOffset + margin[alignment];
        bound = context.scrollEnd + margin[alignment];
        while (offset < (bound + spacing)) {
            lastNode = node;
            node = context.next();
            if (!node) {
                break;
            }

            //
            // Get node size
            //
            nodeSize = getItemSize ? getItemSize(node.renderNode, context.size) : itemSize;
            nodeSize = (nodeSize === true) ? context.resolveSize(node, size)[direction] : nodeSize;

            //
            // Position node
            //
            set.size[direction] = nodeSize;
            set.translate[direction] = offset + (alignment ? spacing : 0);
            set.scrollLength = nodeSize + spacing;
            context.set(node, set);
            offset += set.scrollLength;

            //
            // Keep track of the last section before the first visible cell
            //
            if (isSectionCallback && isSectionCallback(node.renderNode)) {
                if ((set.translate[direction] <= margin[0]) && !lastSectionBeforeVisibleCellTopReached) {
                    lastSectionBeforeVisibleCellTopReached = true;
                    set.translate[direction] = margin[0];
                    context.set(node, set);
                }
                if (!firstVisibleCell) {
                    lastSectionBeforeVisibleCell = node;
                    lastSectionBeforeVisibleCellOffset = offset - nodeSize;
                    lastSectionBeforeVisibleCellLength = nodeSize;
                    lastSectionBeforeVisibleCellScrollLength = nodeSize;
                }
                else if (lastCellOffsetInFirstVisibleSection === undefined) {
                    lastCellOffsetInFirstVisibleSection = offset - nodeSize;
                }
            }
            else if (!firstVisibleCell && (offset >= 0)) {
                firstVisibleCell = node;
            }
        }
        if (lastNode && !node && !alignment) {
            set.scrollLength = nodeSize + margin[0] + -margin[1];
            context.set(lastNode, set);
        }

        //
        // Process previous nodes
        //
        lastNode = undefined;
        node = undefined;
        offset = context.scrollOffset + margin[alignment];
        bound = context.scrollStart + margin[alignment];
        while (offset > (bound - spacing)) {
            lastNode = node;
            node = context.prev();
            if (!node) {
                break;
            }

            //
            // Get node size
            //
            nodeSize = getItemSize ? getItemSize(node.renderNode, context.size) : itemSize;
            nodeSize = (nodeSize === true) ? context.resolveSize(node, size)[direction] : nodeSize;

            //
            // Position node
            //
            set.scrollLength = nodeSize + spacing;
            offset -= set.scrollLength;
            set.size[direction] = nodeSize;
            set.translate[direction] = offset + (alignment ? spacing : 0);
            context.set(node, set);

            //
            // Keep track of the last section before the first visible cell
            //
            if (isSectionCallback && isSectionCallback(node.renderNode)) {
                if ((set.translate[direction] <= margin[0]) && !lastSectionBeforeVisibleCellTopReached) {
                    lastSectionBeforeVisibleCellTopReached = true;
                    set.translate[direction] = margin[0];
                    context.set(node, set);
                }
                if (!lastSectionBeforeVisibleCell) {
                    lastSectionBeforeVisibleCell = node;
                    lastSectionBeforeVisibleCellOffset = offset;
                    lastSectionBeforeVisibleCellLength = nodeSize;
                    lastSectionBeforeVisibleCellScrollLength = set.scrollLength;
                }
            }
            else if ((offset + nodeSize) >= 0) {
                firstVisibleCell = node;
                if (lastSectionBeforeVisibleCell) {
                    lastCellOffsetInFirstVisibleSection = offset + nodeSize;
                }
                lastSectionBeforeVisibleCell = undefined;
            }
        }
        if (lastNode && !node && alignment) {
            set.scrollLength = nodeSize + margin[0] + -margin[1];
            context.set(lastNode, set);
            if (lastSectionBeforeVisibleCell === lastNode) {
                lastSectionBeforeVisibleCellScrollLength = set.scrollLength;
            }
        }

        //
        // When no first section is in the scrollable range, then
        // look back further in search for that section
        //
        if (isSectionCallback && !lastSectionBeforeVisibleCell) {
            node = context.prev();
            while (node) {
                if (isSectionCallback(node.renderNode)) {
                    lastSectionBeforeVisibleCell = node;
                    nodeSize = options.itemSize || context.resolveSize(node, size)[direction];
                    lastSectionBeforeVisibleCellOffset = offset - nodeSize;
                    lastSectionBeforeVisibleCellLength = nodeSize;
                    lastSectionBeforeVisibleCellScrollLength = undefined;
                    break;
                }
                else {
                    node = context.prev();
                }
            }
        }

        //
        // Reposition "last section before first visible cell" to the top of the layout
        //
        if (lastSectionBeforeVisibleCell) {
            var correctedOffset = Math.max(margin[0], lastSectionBeforeVisibleCellOffset);
            if ((lastCellOffsetInFirstVisibleSection !== undefined) &&
                (lastSectionBeforeVisibleCellLength > (lastCellOffsetInFirstVisibleSection - margin[0]))) {
                correctedOffset = ((lastCellOffsetInFirstVisibleSection - lastSectionBeforeVisibleCellLength));
            }
            set.size[direction] = lastSectionBeforeVisibleCellLength;
            set.translate[direction] = correctedOffset;
            set.scrollLength = lastSectionBeforeVisibleCellScrollLength;
            context.set(lastSectionBeforeVisibleCell, set);
        }
    }
function ListLayout(context, options) {

        // Local data
        var size = context.size;
        var direction = context.direction;
        var alignment = context.alignment;
        var revDirection = direction ? 0 : 1;
        var offset;
        var margins = LayoutUtility.normalizeMargins(options.margins);
        var spacing = options.spacing || 0;
        var node;
        var nodeSize;
        var itemSize;
        var getItemSize;
        var lastSectionBeforeVisibleCell;
        var lastSectionBeforeVisibleCellOffset;
        var lastSectionBeforeVisibleCellLength;
        var lastSectionBeforeVisibleCellScrollLength;
        var lastSectionBeforeVisibleCellTopReached;
        var firstVisibleCell;
        var lastNode;
        var lastCellOffsetInFirstVisibleSection;
        var isSectionCallback = options.isSectionCallback;
        var bound;

        //
        // Sanity checks
        //
        if (spacing && typeof spacing !== 'number') {
            console.log('Famous-flex warning: ListLayout was initialized with a non-numeric spacing option. ' + // eslint-disable-line no-console
                'The CollectionLayout supports an array spacing argument, but the ListLayout does not.');
        }

        //
        // Reset size & translation
        //
        set.size[0] = size[0];
        set.size[1] = size[1];
        set.size[revDirection] -= (margins[1 - revDirection] + margins[3 - revDirection]);
        set.translate[0] = 0;
        set.translate[1] = 0;
        set.translate[2] = 0;
        set.translate[revDirection] = margins[direction ? 3 : 0];

        //
        // Determine item-size or use true=size
        //
        if ((options.itemSize === true) || !options.hasOwnProperty('itemSize')) {
            itemSize = true;
        }
        else if (options.itemSize instanceof Function) {
            getItemSize = options.itemSize;
        }
        else {
            itemSize = (options.itemSize === undefined) ? size[direction] : options.itemSize;
        }

        //
        // Determine leading/trailing margins
        //
        margin[0] = margins[direction ? 0 : 3];
        margin[1] = -margins[direction ? 2 : 1];

        //
        // Process all next nodes
        //
        offset = context.scrollOffset + margin[alignment];
        bound = context.scrollEnd + margin[alignment];
        while (offset < (bound + spacing)) {
            lastNode = node;
            node = context.next();
            if (!node) {
                break;
            }

            //
            // Get node size
            //
            nodeSize = getItemSize ? getItemSize(node.renderNode, context.size) : itemSize;
            nodeSize = (nodeSize === true) ? context.resolveSize(node, size)[direction] : nodeSize;

            //
            // Position node
            //
            set.size[direction] = nodeSize;
            set.translate[direction] = offset + (alignment ? spacing : 0);
            set.scrollLength = nodeSize + spacing;
            context.set(node, set);
            offset += set.scrollLength;

            //
            // Keep track of the last section before the first visible cell
            //
            if (isSectionCallback && isSectionCallback(node.renderNode)) {
                if ((set.translate[direction] <= margin[0]) && !lastSectionBeforeVisibleCellTopReached) {
                    lastSectionBeforeVisibleCellTopReached = true;
                    set.translate[direction] = margin[0];
                    context.set(node, set);
                }
                if (!firstVisibleCell) {
                    lastSectionBeforeVisibleCell = node;
                    lastSectionBeforeVisibleCellOffset = offset - nodeSize;
                    lastSectionBeforeVisibleCellLength = nodeSize;
                    lastSectionBeforeVisibleCellScrollLength = nodeSize;
                }
                else if (lastCellOffsetInFirstVisibleSection === undefined) {
                    lastCellOffsetInFirstVisibleSection = offset - nodeSize;
                }
            }
            else if (!firstVisibleCell && (offset >= 0)) {
                firstVisibleCell = node;
            }
        }
        if (lastNode && !node && !alignment) {
            set.scrollLength = nodeSize + margin[0] + -margin[1];
            context.set(lastNode, set);
        }

        //
        // Process previous nodes
        //
        lastNode = undefined;
        node = undefined;
        offset = context.scrollOffset + margin[alignment];
        bound = context.scrollStart + margin[alignment];
        while (offset > (bound - spacing)) {
            lastNode = node;
            node = context.prev();
            if (!node) {
                break;
            }

            //
            // Get node size
            //
            nodeSize = getItemSize ? getItemSize(node.renderNode, context.size) : itemSize;
            nodeSize = (nodeSize === true) ? context.resolveSize(node, size)[direction] : nodeSize;

            //
            // Position node
            //
            set.scrollLength = nodeSize + spacing;
            offset -= set.scrollLength;
            set.size[direction] = nodeSize;
            set.translate[direction] = offset + (alignment ? spacing : 0);
            context.set(node, set);

            //
            // Keep track of the last section before the first visible cell
            //
            if (isSectionCallback && isSectionCallback(node.renderNode)) {
                if ((set.translate[direction] <= margin[0]) && !lastSectionBeforeVisibleCellTopReached) {
                    lastSectionBeforeVisibleCellTopReached = true;
                    set.translate[direction] = margin[0];
                    context.set(node, set);
                }
                if (!lastSectionBeforeVisibleCell) {
                    lastSectionBeforeVisibleCell = node;
                    lastSectionBeforeVisibleCellOffset = offset;
                    lastSectionBeforeVisibleCellLength = nodeSize;
                    lastSectionBeforeVisibleCellScrollLength = set.scrollLength;
                }
            }
            else if ((offset + nodeSize) >= 0) {
                firstVisibleCell = node;
                if (lastSectionBeforeVisibleCell) {
                    lastCellOffsetInFirstVisibleSection = offset + nodeSize;
                }
                lastSectionBeforeVisibleCell = undefined;
            }
        }
        if (lastNode && !node && alignment) {
            set.scrollLength = nodeSize + margin[0] + -margin[1];
            context.set(lastNode, set);
            if (lastSectionBeforeVisibleCell === lastNode) {
                lastSectionBeforeVisibleCellScrollLength = set.scrollLength;
            }
        }

        //
        // When no first section is in the scrollable range, then
        // look back further in search for that section
        //
        if (isSectionCallback && !lastSectionBeforeVisibleCell) {
            node = context.prev();
            while (node) {
                if (isSectionCallback(node.renderNode)) {
                    lastSectionBeforeVisibleCell = node;
                    nodeSize = options.itemSize || context.resolveSize(node, size)[direction];
                    lastSectionBeforeVisibleCellOffset = offset - nodeSize;
                    lastSectionBeforeVisibleCellLength = nodeSize;
                    lastSectionBeforeVisibleCellScrollLength = undefined;
                    break;
                }
                else {
                    node = context.prev();
                }
            }
        }

        //
        // Reposition "last section before first visible cell" to the top of the layout
        //
        if (lastSectionBeforeVisibleCell) {
            var correctedOffset = Math.max(margin[0], lastSectionBeforeVisibleCellOffset);
            if ((lastCellOffsetInFirstVisibleSection !== undefined) &&
                (lastSectionBeforeVisibleCellLength > (lastCellOffsetInFirstVisibleSection - margin[0]))) {
                correctedOffset = ((lastCellOffsetInFirstVisibleSection - lastSectionBeforeVisibleCellLength));
            }
            set.size[direction] = lastSectionBeforeVisibleCellLength;
            set.translate[direction] = correctedOffset;
            set.scrollLength = lastSectionBeforeVisibleCellScrollLength;
            context.set(lastSectionBeforeVisibleCell, set);
        }
    }
function ListLayout ( context , options ) { // Local data var size = context . size ; var direction = context . direction ; var alignment = context . alignment ; var revDirection = direction ? 0 : 1 ; var offset ; var margins = LayoutUtility . normalizeMargins ( options . margins ) ; var spacing = options . spacing || 0 ; var node ; var nodeSize ; var itemSize ; var getItemSize ; var lastSectionBeforeVisibleCell ; var lastSectionBeforeVisibleCellOffset ; var lastSectionBeforeVisibleCellLength ; var lastSectionBeforeVisibleCellScrollLength ; var lastSectionBeforeVisibleCellTopReached ; var firstVisibleCell ; var lastNode ; var lastCellOffsetInFirstVisibleSection ; var isSectionCallback = options . isSectionCallback ; var bound ; // // Sanity checks // if ( spacing && typeof spacing !== 'number' ) { console . log ( 'Famous-flex warning: ListLayout was initialized with a non-numeric spacing option. ' + // eslint-disable-line no-console 'The CollectionLayout supports an array spacing argument, but the ListLayout does not.' ) ; } // // Reset size & translation // set . size [ 0 ] = size [ 0 ] ; set . size [ 1 ] = size [ 1 ] ; set . size [ revDirection ] -= ( margins [ 1 - revDirection ] + margins [ 3 - revDirection ] ) ; set . translate [ 0 ] = 0 ; set . translate [ 1 ] = 0 ; set . translate [ 2 ] = 0 ; set . translate [ revDirection ] = margins [ direction ? 3 : 0 ] ; // // Determine item-size or use true=size // if ( ( options . itemSize === true ) || ! options . hasOwnProperty ( 'itemSize' ) ) { itemSize = true ; } else if ( options . itemSize instanceof Function ) { getItemSize = options . itemSize ; } else { itemSize = ( options . itemSize === undefined ) ? size [ direction ] : options . itemSize ; } // // Determine leading/trailing margins // margin [ 0 ] = margins [ direction ? 0 : 3 ] ; margin [ 1 ] = - margins [ direction ? 2 : 1 ] ; // // Process all next nodes // offset = context . scrollOffset + margin [ alignment ] ; bound = context . scrollEnd + margin [ alignment ] ; while ( offset < ( bound + spacing ) ) { lastNode = node ; node = context . next ( ) ; if ( ! node ) { break ; } // // Get node size // nodeSize = getItemSize ? getItemSize ( node . renderNode , context . size ) : itemSize ; nodeSize = ( nodeSize === true ) ? context . resolveSize ( node , size ) [ direction ] : nodeSize ; // // Position node // set . size [ direction ] = nodeSize ; set . translate [ direction ] = offset + ( alignment ? spacing : 0 ) ; set . scrollLength = nodeSize + spacing ; context . set ( node , set ) ; offset += set . scrollLength ; // // Keep track of the last section before the first visible cell // if ( isSectionCallback && isSectionCallback ( node . renderNode ) ) { if ( ( set . translate [ direction ] <= margin [ 0 ] ) && ! lastSectionBeforeVisibleCellTopReached ) { lastSectionBeforeVisibleCellTopReached = true ; set . translate [ direction ] = margin [ 0 ] ; context . set ( node , set ) ; } if ( ! firstVisibleCell ) { lastSectionBeforeVisibleCell = node ; lastSectionBeforeVisibleCellOffset = offset - nodeSize ; lastSectionBeforeVisibleCellLength = nodeSize ; lastSectionBeforeVisibleCellScrollLength = nodeSize ; } else if ( lastCellOffsetInFirstVisibleSection === undefined ) { lastCellOffsetInFirstVisibleSection = offset - nodeSize ; } } else if ( ! firstVisibleCell && ( offset >= 0 ) ) { firstVisibleCell = node ; } } if ( lastNode && ! node && ! alignment ) { set . scrollLength = nodeSize + margin [ 0 ] + - margin [ 1 ] ; context . set ( lastNode , set ) ; } // // Process previous nodes // lastNode = undefined ; node = undefined ; offset = context . scrollOffset + margin [ alignment ] ; bound = context . scrollStart + margin [ alignment ] ; while ( offset > ( bound - spacing ) ) { lastNode = node ; node = context . prev ( ) ; if ( ! node ) { break ; } // // Get node size // nodeSize = getItemSize ? getItemSize ( node . renderNode , context . size ) : itemSize ; nodeSize = ( nodeSize === true ) ? context . resolveSize ( node , size ) [ direction ] : nodeSize ; // // Position node // set . scrollLength = nodeSize + spacing ; offset -= set . scrollLength ; set . size [ direction ] = nodeSize ; set . translate [ direction ] = offset + ( alignment ? spacing : 0 ) ; context . set ( node , set ) ; // // Keep track of the last section before the first visible cell // if ( isSectionCallback && isSectionCallback ( node . renderNode ) ) { if ( ( set . translate [ direction ] <= margin [ 0 ] ) && ! lastSectionBeforeVisibleCellTopReached ) { lastSectionBeforeVisibleCellTopReached = true ; set . translate [ direction ] = margin [ 0 ] ; context . set ( node , set ) ; } if ( ! lastSectionBeforeVisibleCell ) { lastSectionBeforeVisibleCell = node ; lastSectionBeforeVisibleCellOffset = offset ; lastSectionBeforeVisibleCellLength = nodeSize ; lastSectionBeforeVisibleCellScrollLength = set . scrollLength ; } } else if ( ( offset + nodeSize ) >= 0 ) { firstVisibleCell = node ; if ( lastSectionBeforeVisibleCell ) { lastCellOffsetInFirstVisibleSection = offset + nodeSize ; } lastSectionBeforeVisibleCell = undefined ; } } if ( lastNode && ! node && alignment ) { set . scrollLength = nodeSize + margin [ 0 ] + - margin [ 1 ] ; context . set ( lastNode , set ) ; if ( lastSectionBeforeVisibleCell === lastNode ) { lastSectionBeforeVisibleCellScrollLength = set . scrollLength ; } } // // When no first section is in the scrollable range, then // look back further in search for that section // if ( isSectionCallback && ! lastSectionBeforeVisibleCell ) { node = context . prev ( ) ; while ( node ) { if ( isSectionCallback ( node . renderNode ) ) { lastSectionBeforeVisibleCell = node ; nodeSize = options . itemSize || context . resolveSize ( node , size ) [ direction ] ; lastSectionBeforeVisibleCellOffset = offset - nodeSize ; lastSectionBeforeVisibleCellLength = nodeSize ; lastSectionBeforeVisibleCellScrollLength = undefined ; break ; } else { node = context . prev ( ) ; } } } // // Reposition "last section before first visible cell" to the top of the layout // if ( lastSectionBeforeVisibleCell ) { var correctedOffset = Math . max ( margin [ 0 ] , lastSectionBeforeVisibleCellOffset ) ; if ( ( lastCellOffsetInFirstVisibleSection !== undefined ) && ( lastSectionBeforeVisibleCellLength > ( lastCellOffsetInFirstVisibleSection - margin [ 0 ] ) ) ) { correctedOffset = ( ( lastCellOffsetInFirstVisibleSection - lastSectionBeforeVisibleCellLength ) ) ; } set . size [ direction ] = lastSectionBeforeVisibleCellLength ; set . translate [ direction ] = correctedOffset ; set . scrollLength = lastSectionBeforeVisibleCellScrollLength ; context . set ( lastSectionBeforeVisibleCell , set ) ; } }
Layout function
Layout function