the-riddle
clone your own copy | download snapshot

Snapshots | iceberg

Inside this repository

book2.js
application/javascript

Download raw (7.7 KB)

;(function () {
    'use strict';

    function replaceImages () {
        var im, wrapper, clsName, imgs = document.querySelectorAll("#main img");

        for (var i=0;i<imgs.length;i++) {
            im = imgs[i];
            wrapper = document.createElement("div");
            wrapper.classList.add("img");
            while (im.classList.length > 0) {
                clsName = im.classList[0];
                wrapper.classList.add(clsName);
                im.classList.remove(clsName);
            }
            wrapper.appendChild(im.cloneNode());
            im.parentNode.replaceChild(wrapper, im);
        }
        
    }

    function insertBreakBefore (refNode, className) {
        var brkNode = document.createElement('div');
        brkNode.classList.add('break-before');
        brkNode.classList.add(className);
        refNode.parentElement.insertBefore(brkNode, refNode);
    }

    function getNodeIndex(node) {
        return Array.prototype.indexOf.call(node.parentElement.childNodes, node);
    }

    /**
     * Returns first region the given node is shown within
     * 
     * workaround for getRegionsForContent() as that function only seems to work 
     * on block-elements
     */
    function getRegionForNode(flow, node) {
        var ranges, regions = flow.getRegions();
        for (var i=0; i < regions.length; i++) {
            ranges = regions[i].webkitGetRegionFlowRanges();

            for (var r=0; r < ranges.length; r++) {
                if (ranges[r].isPointInRange(node)) {
                    return regions[i];
                }
            }
        }
        console.log('Could not find region for node');
    }

    /**
     * Find page for given node, travels up the DOM tree to find
     * first wrapping paper element. Does not work for Nodes in a flow.
     */
    function getPage (node) {
        if (node) {
            if (node.classList.contains('paper')) {
                return node;
            }
            else {
                if (node.parentElement) {
                    return getPage(node.parentElement);
                }
                else {
                    return false;
                }
            }
        }
        else {
            return false;
        }
    }
    
    function doLayout() {
        var images = document.querySelectorAll('#main .img'),
            flows = document.webkitGetNamedFlows(),
            contentFlow = flows.namedItem("main"),
            imageFlow = flows.namedItem("images"),
            captionFlow = flows.namedItem("figcaptions"),
            imageOffset = 0,
            master = document.querySelector('#master-page'),
            container = master.parentNode;
        
        container.removeChild(master);
        master.removeAttribute('id');

        function addPages(amount) {
            var page, pagenum;

            for (var i=0;i<amount;i++) {
                page = master.cloneNode(true);
                container.appendChild(page);
                pagenum = document.querySelectorAll('.paper').length;
                page.setAttribute('id', 'page-'+pagenum);
                if (pagenum == 1) {
                    page.classList.add('cover');
                }
            }
        }

        function doubleTextContainers (callback) {
            var imageRegions = imageFlow.getRegions();

            for (var i=0; i < imageRegions.length; i++) {
                if (imageRegions[i].webkitGetRegionFlowRanges().length < 1) {
                    getPage(imageRegions[i]).classList.add('reveal_secondary_main');
                }
            }

            callback();
        } 

        function alignImageCaptions(callback) {
            var im, caption, imageRegion, captionRegion, imagePageNum, captionPageNum;

            if (imageOffset >= images.length) {
                return doubleTextContainers(callback);
            }

            im = images[imageOffset],
            imageRegion = getRegionForNode(imageFlow, im);

            if (imageRegion) {
                imagePageNum = parseInt(getPage(imageRegion).id.replace(/\D/g, ''));
                if (im.classList.contains('full')) {
                    getPage(imageRegion).classList.add('full');
                }
                else if (im.classList.contains('half')) {
                    getPage(imageRegion).classList.add('half');
                    // Only if the next image is also half, and we are not already in a secondary region
                    // show the the next 'half image container'
                    if (!imageRegion.classList.contains('secondary') && images.length > (imageOffset + 1) && images[imageOffset+1].classList.contains('half')) {
                        getPage(imageRegion).classList.add('reveal_secondary_images');
                        images[imageOffset+1].classList.add('break-after')
                    }
                }

                imageRegion = getRegionForNode(imageFlow, im),
                imagePageNum = parseInt(getPage(imageRegion).id.replace(/\D/g, ''));

                var caption = im.nextElementSibling;
                
                if (caption) {
                    var captionRegion = getRegionForNode(captionFlow, caption);

                    if (captionRegion) {
                        captionPageNum = parseInt(getPage(captionRegion).id.replace(/\D/g, ''));
                        var limit = 5;

                        while (imagePageNum > captionPageNum && limit > 0) {
                            insertBreakBefore(caption, 'figcaption');

                            captionRegion = getRegionForNode(captionFlow, caption),
                            captionPageNum = parseInt(getPage(captionRegion).id.replace(/\D/g, ''));
                            limit--;
                        }
                    }
                } else {
                    console.log('No caption for', im)
                }
                
                imageOffset++;
                window.requestAnimationFrame(function () { alignImageCaptions(callback); });
            }
        }

        function findFirstEmptyPage (flow) {
            var regions = flow.getRegions();
            for (var i=0; i<regions.length;i++) {
                if (regions[i].webkitRegionOverset == 'empty' && !regions[i].classList.contains('secondary')) {
                    return getPage(regions[i]);
                }
            }
        }

        function getPageNum (page) {
            return parseInt(page.id.replace(/\D/g, ''));
        }

        function flowContent () {
            if (contentFlow.overset || imageFlow.overset || captionFlow.overset) {
                addPages(25);
                window.requestAnimationFrame(function () { alignImageCaptions(flowContent) });
            } else {
                var flows = [contentFlow, imageFlow, captionFlow], firstEmptyPageNum = -1;
                for (var f=0;f<flows.length;f++) {
                    var flowFirstEmptyPageNum = getPageNum(findFirstEmptyPage(flows[f]));
                    // console.log(flowFirstEmptyPageNum);
                    if (flowFirstEmptyPageNum > firstEmptyPageNum) {
                        firstEmptyPageNum = flowFirstEmptyPageNum;
                    }
                }

                // console.log(firstEmptyPageNum);

                var lastPageWithContent = document.querySelector('#page-' + (firstEmptyPageNum - 1));

                console.log(lastPageWithContent);

                while (lastPageWithContent.nextSibling) {
                    lastPageWithContent.parentNode.removeChild(lastPageWithContent.nextSibling);
                }

                document.layoutcomplete = true;
                console.log('layout done');
            }
        }
        
        flowContent();
    }

    document.addEventListener("storiesloaded", function () {
        replaceImages();
        doLayout();
    }, false);
})();