<commit_before>define(['require', 'module', 'jquery', 'underscore', 'backbone', 'URIjs', './manifest', './spine', './metadata',
    './page_spread_property'],
    function (require, module, $, _, Backbone, URI, Manifest, Spine, Metadata, PageSpreadProperty) {
    console.log('package_document module id: ' + module.id);

    // Description: This model provides an interface for navigating an EPUB's package document
    var PackageDocument = function(packageDocumentURL, jsonData, resourceFetcher) {

        var _spine = new Spine(jsonData.spine);
        var _manifest = new Manifest(jsonData.manifest);
        var _metadata = new Metadata(jsonData.metadata);
        var _bindings = new Spine(jsonData.bindings);
        var _pageSpreadProperty = new PageSpreadProperty();

        // If this book is fixed layout, assign the page spread class
        if (isFixedLayout()) {
            assignPageSpreadClass();
        }

        this.getPackageData = function () {

            var spinePackageData = [];
            var packageDocRoot = packageDocumentURL.substr(0, packageDocumentURL.lastIndexOf("/"));

            _spine.each(function (spineItem) {
                spinePackageData.push(generatePackageData(spineItem));
            });

            // This is where the package data format thing is generated
            return {
                rootUrl : packageDocRoot,
                rendition_layout : isFixedLayout(),
                spine : {
                    direction : pageProgressionDirection(),
                    items : spinePackageData
                }
            };
        };

        function isFixedLayout() {

            return _metadata.get("fixed_layout");
        }

        function getManifestItemById(id) {

            var foundManifestItem = _manifest.find(
                function (manifestItem) {
                    if (manifestItem.get("id") === id) {
                        return manifestItem;
                    }

                    return undefined;
                });

            if (foundManifestItem) {
                return foundManifestItem.toJSON();
            }
            else {
                return undefined;
            }
        }

        function getManifestItemByIdref(idref) {

            var foundManifestItem = getManifestItemById(idref);
            if (foundManifestItem) {
                return foundManifestItem;
            }
            else {
                return undefined;
            }
        }

        function getSpineItemByIdref(idref) {

            var foundSpineItem = getSpineModelByIdref(idref);
            if (foundSpineItem) {
                return foundSpineItem.toJSON();
            }
            else {
                return undefined;
            }
        }

        function getSpineItem(spineIndex) {

            var spineItem = _spine.at(spineIndex);
            if (spineItem) {
                return spineItem.toJSON();
            }
            else {
                return undefined;
            }
        }

        function spineLength() {
            return _spine.length;
        }

        // Description: gets the next position in the spine for which the
        // spineItem does not have `linear='no'`. The start
        // param is the non-inclusive position to begin the search
        // from. If start is not supplied, the search will begin at
        // postion 0. If no linear position can be found, this
        // function returns undefined
        function getNextLinearSpinePosition(currSpineIndex) {

            if (currSpineIndex === undefined || currSpineIndex < 0) {
                currSpineIndex = 0;

                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            while (currSpineIndex < spineLength() - 1) {
                currSpineIndex += 1;
                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            // No next linear spine position.
            return undefined;
        }

        // Description: gets the previous position in the spine for which the
        // spineItem does not have `linear='no'`. The start
        // param is the non-inclusive position to begin the search
        // from. If start is not supplied, the search will begin at
        // the end of the spine. If no linear position can be found,
        // this function returns undefined
        function getPrevLinearSpinePosition(currSpineIndex) {

            if (currSpineIndex === undefined || currSpineIndex > spineLength() - 1) {
                currSpineIndex = spineLength() - 1;

                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            while (currSpineIndex > 0) {
                currSpineIndex -= 1;
                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            // No previous linear spine position.
            return undefined;
        }

        function hasNextSection(currSpineIndex) {

            if (currSpineIndex >= 0 &&
                currSpineIndex <= spineLength() - 1) {

                return getNextLinearSpinePosition(currSpineIndex) > -1;
            }
            else {
                return false;
            }
        }

        function hasPrevSection(currSpineIndex) {

            if (currSpineIndex >= 0 &&
                currSpineIndex <= spineLength() - 1) {

                return getPrevLinearSpinePosition(currSpineIndex) > -1;
            }
            else {
                return false;
            }
        }

        function pageProgressionDirection() {

            if (_metadata.get("page_prog_dir") === "rtl") {
                return "rtl";
            }
            else if (_metadata.get("page_prog_dir") === "default") {
                return "default";
            }
            else {
                return "ltr";
            }
        }

        function getSpineIndexByHref(manifestHref) {

            var spineItem = getSpineModelFromHref(manifestHref);
            return getSpineIndex(spineItem);
        }

        function getBindingByHandler(handler) {

            var binding = _bindings.find(
                function (binding) {

                    if (binding.get("handler") === handler) {
                        return binding;
                    }
                });

            if (binding) {
                return binding.toJSON();
            }
            else {
                return undefined;
            }
        }

        function generatePackageData(spineItem) {

            var fixedLayoutProperty = "reflowable";
            // var fixedLayoutType = undefined;
            var manifestItem = getManifestModelByIdref(spineItem.get("idref"));
            // var isLinear;
            // var firstPageIsOffset;
            var pageSpread;

            // Get fixed layout properties
            if (spineItem.isFixedLayout() || isFixedLayout()) {

                fixedLayoutProperty = "pre-paginated";
                // if (manifestItem.isSvg()) {
                //     fixedLayoutType = "svg";
                // }
                // else if (manifestItem.isImage()) {
                //     fixedLayoutType = "image";
                // }
                // else {
                //     fixedLayoutType = "xhtml";
                // }
            }

            // Set primary reading order attribute
            // if (spineItem.get("linear").trim() === "no") {
            //     isLinear = false;
            // }
            // else {
            //     isLinear = true;
            // }

            pageSpread = spineItem.get("page_spread");
            // Set first page is offset parameter
            // if (!isFixedLayout) {
            //     if (pageProgressionDirection() === "ltr" && pageSpread === "right") {
            //         firstPageIsOffset = true;
            //     }
            //     else if (pageProgressionDirection() === "rtl" && pageSpread === "left") {
            //         firstPageIsOffset = true;
            //     }
            //     else {
            //         firstPageIsOffset = false;
            //     }
            // }

            if (pageSpread === "left") {
                pageSpread = "page-spread-left";
            }
            else if (pageSpread === "right") {
                pageSpread = "page-spread-right";
            }
            else if (pageSpread === "center") {
                pageSpread = "page-spread-center";
            }

            var spineInfo = {
                href : manifestItem.get('contentDocumentURI'),
                media_type : manifestItem.get('media_type'),
                media_overlay : manifestItem.get('media_overlay'),
                idref : spineItem.get("idref"),
                page_spread : pageSpread,
                rendition_layout : fixedLayoutProperty
            };

            return spineInfo;
        }

        function getToc() {

            var item = getTocItem();
            if (item) {
                return item.get("contentDocumentURI");
            }
            return null;
        }

        function getTocText(callback) {

            var tocUrl = getToc();
            console.log('tocUrl: [' + tocUrl + ']');

            resourceFetcher.relativeToPackageFetchFileContents(tocUrl, 'text', function (tocDocumentText) {
                callback(tocDocumentText)
            }, function (err) {
                console.error('ERROR fetching TOC from [' + getToc() + ']:');
                console.error(err);
                callback(undefined);
            });
        }

        function getTocDom(callback) {

            getTocText(function (tocText) {
                if (typeof tocText === 'string') {
                    var tocDom = (new DOMParser()).parseFromString(tocText, "text/xml");
                    callback(tocDom);
                } else {
                    callback(undefined);
                }
            });
        }

        function generateTocListDOM(callback) {

            getTocDom(function (tocDom) {
                if (tocDom) {
                    if (tocIsNcx()) {
                        var $ncxOrderedList;
                        $ncxOrderedList = getNcxOrderedList($("navMap", tocDom));
                        callback($ncxOrderedList[0]);
                    } else {
                        var packageDocumentAbsoluteURL = new URI(packageDocumentURL).absoluteTo(document.URL);
                        var tocDocumentAbsoluteURL = new URI(getToc()).absoluteTo(packageDocumentAbsoluteURL);
                        // add a BASE tag to change the TOC document's baseURI.
                        var oldBaseTag = $(tocDom).remove('base');
                        var newBaseTag = $('<base></base>');
                        $(newBaseTag).attr('href', tocDocumentAbsoluteURL);
                        $(tocDom).find('head').append(newBaseTag);
                        // TODO: fix TOC hrefs both for exploded in zipped EPUBs
                        callback(tocDom);
                    }
                } else {
                    callback(undefined);
                }
            });
        }

        function tocIsNcx() {

            var tocItem = getTocItem();
            var contentDocURI = tocItem.get("contentDocumentURI");
            var fileExtension = contentDocURI.substr(contentDocURI.lastIndexOf('.') + 1);

            return fileExtension.trim().toLowerCase() === "ncx";
        }

        // ----------------------- PRIVATE HELPERS -------------------------------- //

        function getNcxOrderedList($navMapDOM) {

            var $ol = $("

");
            $.each($navMapDOM.children("navPoint"), function (index, navPoint) {
                addNavPointElements($(navPoint), $ol);
            });
            return $ol;
        }

        // Description: Constructs an html representation of NCX navPoints, based on an object of navPoint information
        // Rationale: This is a recursive method, as NCX navPoint elements can nest 0 or more of themselves as children
        function addNavPointElements($navPointDOM, $ol) {

            // Add the current navPoint element to the TOC html
            var navText = $navPointDOM.children("navLabel").text().trim();
            var navHref = $navPointDOM.children("content").attr("src");
            var $navPointLi = $("
'" + navText + "'
");

            // Append nav point info
            $ol.append($navPointLi);

            // Append ordered list of nav points
            if ($navPointDOM.children("navPoint").length > 0 ) {

                var $newLi = $("

");
                var $newOl = $("

");
                $.each($navPointDOM.children("navPoint"), function (navIndex, navPoint) {
                    $newOl.append(addNavPointElements($(navPoint), $newOl));
                });

                $newLi.append($newOl);
                $ol.append($newLi);
            }
        }

        // Refactoring candidate: This search will always iterate through entire manifest; this should be modified to
        //   return when the manifest item is found.
        function getSpineModelFromHref(manifestHref) {

            var resourceURI = new URI(manifestHref);
            var resourceName = resourceURI.filename();
            var foundSpineModel;

            _manifest.each(function (manifestItem) {

                var manifestItemURI = new URI(manifestItem.get("href"));
                var manifestItemName = manifestItemURI.filename();

                // Rationale: Return a spine model based on the manifest item id, which is the idref of the spine item
                if (manifestItemName === resourceName) {
                    foundSpineModel = getSpineModelByIdref(manifestItem.get("id"));
                }
            });

            return foundSpineModel;
        }

        function getSpineModelByIdref(idref) {

            var foundSpineItem = _spine.find(
                function (spineItem) {
                    if (spineItem.get("idref") === idref) {
                        return spineItem;
                    }
                });

            return foundSpineItem;
        }

        function getManifestModelByIdref(idref) {

            var foundManifestItem = _manifest.find(
                function (manifestItem) {
                    if (manifestItem.get("id") === idref) {
                        return manifestItem;
                    }
                });

            return foundManifestItem;
        }

        function getSpineIndex(spineItem) {

            return _spine.indexOf(spineItem);
        }

        // Description: When rendering fixed layout pages we need to determine whether the page
        //   should be on the left or the right in two up mode, options are:
        //     left_page:      render on the left side
        //     right_page:     render on the right side
        //     center_page:    always center the page horizontally
        //   This property must be assigned when the package document is initialized
        // NOTE: Look into how spine items with the linear="no" property affect this algorithm
        function assignPageSpreadClass() {

            var pageSpreadClass;
            var numSpineItems;

            // If the epub is apple fixed layout
            if (_metadata.get("apple_fixed")) {

                numSpineItems = _spine.length;
                _spine.each(function (spineItem, spineIndex) {

                    pageSpreadClass = _pageSpreadProperty.inferiBooksPageSpread(spineIndex, numSpineItems);
                    spineItem.set({ pageSpreadClass : pageSpreadClass });
                });
            }
            else {
                // For each spine item
                _spine.each(function (spineItem, spineIndex) {

                    if (spineItem.get("page_spread")) {

                        pageSpreadClass = _pageSpreadProperty.getPageSpreadFromProperties(spineItem.get("page_spread"));
                        spineItem.set({ pageSpreadClass : pageSpreadClass });
                    }
                    else {

                        pageSpreadClass = _pageSpreadProperty.inferUnassignedPageSpread(spineIndex, _spine, pageProgressionDirection());
                        spineItem.set({ pageSpreadClass : pageSpreadClass });
                    }
                });
            }
        }

        function getTocItem(){

            var manifest = _manifest;
            var spine_id = _metadata.get("ncx");

            var item = manifest.find(function(item){

                if (item.get("properties").indexOf("nav") !== -1) {
                    return true;
                }
                else {
                    return false;
                }
            });

            if( item ) {
                return item;
            }

            if( spine_id && spine_id.length > 0 ) {
                return manifest.find(function(item) {
                    return item.get("id") === spine_id;
                });
            }

            return null;
        }

        // NOTE: Media overlays are temporarily disabled
        // getMediaOverlayItem : function(idref) {
        //     // just look up the object in the mo_map
        //     var map = this.get("mo_map");
        //     return map && map[idref];
        // },

        this.generateTocListDOM = generateTocListDOM;
    };

    return PackageDocument;
});
<commit_msg>Added a way to access the original toc url<commit_after>define(['require', 'module', 'jquery', 'underscore', 'backbone', 'URIjs', './manifest', './spine', './metadata',
    './page_spread_property'],
    function (require, module, $, _, Backbone, URI, Manifest, Spine, Metadata, PageSpreadProperty) {
    console.log('package_document module id: ' + module.id);

    // Description: This model provides an interface for navigating an EPUB's package document
    var PackageDocument = function(packageDocumentURL, jsonData, resourceFetcher) {

        var _spine = new Spine(jsonData.spine);
        var _manifest = new Manifest(jsonData.manifest);
        var _metadata = new Metadata(jsonData.metadata);
        var _bindings = new Spine(jsonData.bindings);
        var _pageSpreadProperty = new PageSpreadProperty();

        // If this book is fixed layout, assign the page spread class
        if (isFixedLayout()) {
            assignPageSpreadClass();
        }

        this.getPackageData = function () {

            var spinePackageData = [];
            var packageDocRoot = packageDocumentURL.substr(0, packageDocumentURL.lastIndexOf("/"));

            _spine.each(function (spineItem) {
                spinePackageData.push(generatePackageData(spineItem));
            });

            // This is where the package data format thing is generated
            return {
                rootUrl : packageDocRoot,
                rendition_layout : isFixedLayout(),
                spine : {
                    direction : pageProgressionDirection(),
                    items : spinePackageData
                }
            };
        };

        function isFixedLayout() {

            return _metadata.get("fixed_layout");
        }

        function getManifestItemById(id) {

            var foundManifestItem = _manifest.find(
                function (manifestItem) {
                    if (manifestItem.get("id") === id) {
                        return manifestItem;
                    }

                    return undefined;
                });

            if (foundManifestItem) {
                return foundManifestItem.toJSON();
            }
            else {
                return undefined;
            }
        }

        function getManifestItemByIdref(idref) {

            var foundManifestItem = getManifestItemById(idref);
            if (foundManifestItem) {
                return foundManifestItem;
            }
            else {
                return undefined;
            }
        }

        function getSpineItemByIdref(idref) {

            var foundSpineItem = getSpineModelByIdref(idref);
            if (foundSpineItem) {
                return foundSpineItem.toJSON();
            }
            else {
                return undefined;
            }
        }

        function getSpineItem(spineIndex) {

            var spineItem = _spine.at(spineIndex);
            if (spineItem) {
                return spineItem.toJSON();
            }
            else {
                return undefined;
            }
        }

        function spineLength() {
            return _spine.length;
        }

        // Description: gets the next position in the spine for which the
        // spineItem does not have `linear='no'`. The start
        // param is the non-inclusive position to begin the search
        // from. If start is not supplied, the search will begin at
        // postion 0. If no linear position can be found, this
        // function returns undefined
        function getNextLinearSpinePosition(currSpineIndex) {

            if (currSpineIndex === undefined || currSpineIndex < 0) {
                currSpineIndex = 0;

                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            while (currSpineIndex < spineLength() - 1) {
                currSpineIndex += 1;
                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            // No next linear spine position.
            return undefined;
        }

        // Description: gets the previous position in the spine for which the
        // spineItem does not have `linear='no'`. The start
        // param is the non-inclusive position to begin the search
        // from. If start is not supplied, the search will begin at
        // the end of the spine. If no linear position can be found,
        // this function returns undefined
        function getPrevLinearSpinePosition(currSpineIndex) {

            if (currSpineIndex === undefined || currSpineIndex > spineLength() - 1) {
                currSpineIndex = spineLength() - 1;

                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            while (currSpineIndex > 0) {
                currSpineIndex -= 1;
                if (_spine.at(currSpineIndex).get("linear") !== "no") {
                    return currSpineIndex;
                }
            }

            // No previous linear spine position.
            return undefined;
        }

        function hasNextSection(currSpineIndex) {

            if (currSpineIndex >= 0 &&
                currSpineIndex <= spineLength() - 1) {

                return getNextLinearSpinePosition(currSpineIndex) > -1;
            }
            else {
                return false;
            }
        }

        function hasPrevSection(currSpineIndex) {

            if (currSpineIndex >= 0 &&
                currSpineIndex <= spineLength() - 1) {

                return getPrevLinearSpinePosition(currSpineIndex) > -1;
            }
            else {
                return false;
            }
        }

        function pageProgressionDirection() {

            if (_metadata.get("page_prog_dir") === "rtl") {
                return "rtl";
            }
            else if (_metadata.get("page_prog_dir") === "default") {
                return "default";
            }
            else {
                return "ltr";
            }
        }

        function getSpineIndexByHref(manifestHref) {

            var spineItem = getSpineModelFromHref(manifestHref);
            return getSpineIndex(spineItem);
        }

        function getBindingByHandler(handler) {

            var binding = _bindings.find(
                function (binding) {

                    if (binding.get("handler") === handler) {
                        return binding;
                    }
                });

            if (binding) {
                return binding.toJSON();
            }
            else {
                return undefined;
            }
        }

        function generatePackageData(spineItem) {

            var fixedLayoutProperty = "reflowable";
            // var fixedLayoutType = undefined;
            var manifestItem = getManifestModelByIdref(spineItem.get("idref"));
            // var isLinear;
            // var firstPageIsOffset;
            var pageSpread;

            // Get fixed layout properties
            if (spineItem.isFixedLayout() || isFixedLayout()) {

                fixedLayoutProperty = "pre-paginated";
                // if (manifestItem.isSvg()) {
                //     fixedLayoutType = "svg";
                // }
                // else if (manifestItem.isImage()) {
                //     fixedLayoutType = "image";
                // }
                // else {
                //     fixedLayoutType = "xhtml";
                // }
            }

            // Set primary reading order attribute
            // if (spineItem.get("linear").trim() === "no") {
            //     isLinear = false;
            // }
            // else {
            //     isLinear = true;
            // }

            pageSpread = spineItem.get("page_spread");
            // Set first page is offset parameter
            // if (!isFixedLayout) {
            //     if (pageProgressionDirection() === "ltr" && pageSpread === "right") {
            //         firstPageIsOffset = true;
            //     }
            //     else if (pageProgressionDirection() === "rtl" && pageSpread === "left") {
            //         firstPageIsOffset = true;
            //     }
            //     else {
            //         firstPageIsOffset = false;
            //     }
            // }

            if (pageSpread === "left") {
                pageSpread = "page-spread-left";
            }
            else if (pageSpread === "right") {
                pageSpread = "page-spread-right";
            }
            else if (pageSpread === "center") {
                pageSpread = "page-spread-center";
            }

            var spineInfo = {
                href : manifestItem.get('contentDocumentURI'),
                media_type : manifestItem.get('media_type'),
                media_overlay : manifestItem.get('media_overlay'),
                idref : spineItem.get("idref"),
                page_spread : pageSpread,
                rendition_layout : fixedLayoutProperty
            };

            return spineInfo;
        }

        function getToc() {

            var item = getTocItem();
            if (item) {
                return item.get("contentDocumentURI");
            }
            return null;
        }

        function getTocText(callback) {

            var tocUrl = getToc();
            console.log('tocUrl: [' + tocUrl + ']');

            resourceFetcher.relativeToPackageFetchFileContents(tocUrl, 'text', function (tocDocumentText) {
                callback(tocDocumentText)
            }, function (err) {
                console.error('ERROR fetching TOC from [' + getToc() + ']:');
                console.error(err);
                callback(undefined);
            });
        }

        function getTocDom(callback) {

            getTocText(function (tocText) {
                if (typeof tocText === 'string') {
                    var tocDom = (new DOMParser()).parseFromString(tocText, "text/xml");
                    callback(tocDom);
                } else {
                    callback(undefined);
                }
            });
        }

        function generateTocListDOM(callback) {

            getTocDom(function (tocDom) {
                if (tocDom) {
                    if (tocIsNcx()) {
                        var $ncxOrderedList;
                        $ncxOrderedList = getNcxOrderedList($("navMap", tocDom));
                        callback($ncxOrderedList[0]);
                    } else {
                        var packageDocumentAbsoluteURL = new URI(packageDocumentURL).absoluteTo(document.URL);
                        var tocDocumentAbsoluteURL = new URI(getToc()).absoluteTo(packageDocumentAbsoluteURL);
                        // add a BASE tag to change the TOC document's baseURI.
                        var oldBaseTag = $(tocDom).remove('base');
                        var newBaseTag = $('<base></base>');
                        $(newBaseTag).attr('href', tocDocumentAbsoluteURL);
                        $(tocDom).find('head').append(newBaseTag);
                        // TODO: fix TOC hrefs both for exploded in zipped EPUBs
                        callback(tocDom);
                    }
                } else {
                    callback(undefined);
                }
            });
        }

        function tocIsNcx() {

            var tocItem = getTocItem();
            var contentDocURI = tocItem.get("contentDocumentURI");
            var fileExtension = contentDocURI.substr(contentDocURI.lastIndexOf('.') + 1);

            return fileExtension.trim().toLowerCase() === "ncx";
        }

        // ----------------------- PRIVATE HELPERS -------------------------------- //

        function getNcxOrderedList($navMapDOM) {

            var $ol = $("

");
            $.each($navMapDOM.children("navPoint"), function (index, navPoint) {
                addNavPointElements($(navPoint), $ol);
            });
            return $ol;
        }

        // Description: Constructs an html representation of NCX navPoints, based on an object of navPoint information
        // Rationale: This is a recursive method, as NCX navPoint elements can nest 0 or more of themselves as children
        function addNavPointElements($navPointDOM, $ol) {

            // Add the current navPoint element to the TOC html
            var navText = $navPointDOM.children("navLabel").text().trim();
            var navHref = $navPointDOM.children("content").attr("src");
            var $navPointLi = $("
'" + navText + "'
");

            // Append nav point info
            $ol.append($navPointLi);

            // Append ordered list of nav points
            if ($navPointDOM.children("navPoint").length > 0 ) {

                var $newLi = $("

");
                var $newOl = $("

");
                $.each($navPointDOM.children("navPoint"), function (navIndex, navPoint) {
                    $newOl.append(addNavPointElements($(navPoint), $newOl));
                });

                $newLi.append($newOl);
                $ol.append($newLi);
            }
        }

        // Refactoring candidate: This search will always iterate through entire manifest; this should be modified to
        //   return when the manifest item is found.
        function getSpineModelFromHref(manifestHref) {

            var resourceURI = new URI(manifestHref);
            var resourceName = resourceURI.filename();
            var foundSpineModel;

            _manifest.each(function (manifestItem) {

                var manifestItemURI = new URI(manifestItem.get("href"));
                var manifestItemName = manifestItemURI.filename();

                // Rationale: Return a spine model based on the manifest item id, which is the idref of the spine item
                if (manifestItemName === resourceName) {
                    foundSpineModel = getSpineModelByIdref(manifestItem.get("id"));
                }
            });

            return foundSpineModel;
        }

        function getSpineModelByIdref(idref) {

            var foundSpineItem = _spine.find(
                function (spineItem) {
                    if (spineItem.get("idref") === idref) {
                        return spineItem;
                    }
                });

            return foundSpineItem;
        }

        function getManifestModelByIdref(idref) {

            var foundManifestItem = _manifest.find(
                function (manifestItem) {
                    if (manifestItem.get("id") === idref) {
                        return manifestItem;
                    }
                });

            return foundManifestItem;
        }

        function getSpineIndex(spineItem) {

            return _spine.indexOf(spineItem);
        }

        // Description: When rendering fixed layout pages we need to determine whether the page
        //   should be on the left or the right in two up mode, options are:
        //     left_page:      render on the left side
        //     right_page:     render on the right side
        //     center_page:    always center the page horizontally
        //   This property must be assigned when the package document is initialized
        // NOTE: Look into how spine items with the linear="no" property affect this algorithm
        function assignPageSpreadClass() {

            var pageSpreadClass;
            var numSpineItems;

            // If the epub is apple fixed layout
            if (_metadata.get("apple_fixed")) {

                numSpineItems = _spine.length;
                _spine.each(function (spineItem, spineIndex) {

                    pageSpreadClass = _pageSpreadProperty.inferiBooksPageSpread(spineIndex, numSpineItems);
                    spineItem.set({ pageSpreadClass : pageSpreadClass });
                });
            }
            else {
                // For each spine item
                _spine.each(function (spineItem, spineIndex) {

                    if (spineItem.get("page_spread")) {

                        pageSpreadClass = _pageSpreadProperty.getPageSpreadFromProperties(spineItem.get("page_spread"));
                        spineItem.set({ pageSpreadClass : pageSpreadClass });
                    }
                    else {

                        pageSpreadClass = _pageSpreadProperty.inferUnassignedPageSpread(spineIndex, _spine, pageProgressionDirection());
                        spineItem.set({ pageSpreadClass : pageSpreadClass });
                    }
                });
            }
        }

        function getTocItem(){

            var manifest = _manifest;
            var spine_id = _metadata.get("ncx");

            var item = manifest.find(function(item){

                if (item.get("properties").indexOf("nav") !== -1) {
                    return true;
                }
                else {
                    return false;
                }
            });

            if( item ) {
                return item;
            }

            if( spine_id && spine_id.length > 0 ) {
                return manifest.find(function(item) {
                    return item.get("id") === spine_id;
                });
            }

            return null;
        }

        // NOTE: Media overlays are temporarily disabled
        // getMediaOverlayItem : function(idref) {
        //     // just look up the object in the mo_map
        //     var map = this.get("mo_map");
        //     return map && map[idref];
        // },

        this.generateTocListDOM = generateTocListDOM;
        this.getTocURL = getToc;
    };

    return PackageDocument;
});
<|endoftext|>


<commit_before>
/**
 * Check and configure MathJax
 */
if (typeof MathJax !== 'undefined'){
    exports.MathJax = true;

    MathJax.Hub.Config({
        messageStyle: 'none',
        skipStartupTypeset: true,
        displayAlign: "left",
        tex2jax: {
            inlineMath: [["$","$"],["\\(","\\)"]]
        }
    });

    MathJax.Hub.Configured();
} else {
    exports.MathJax = false;
}
<commit_msg>lint config.js<commit_after>/* global MathJax:false */

/**
 * Check and configure MathJax
 */
if (typeof MathJax !== 'undefined'){
    exports.MathJax = true;

    MathJax.Hub.Config({
        messageStyle: 'none',
        skipStartupTypeset: true,
        displayAlign: 'left',
        tex2jax: {
            inlineMath: [['$','$'],['\\(','\\)']]
        }
    });

    MathJax.Hub.Configured();
} else {
    exports.MathJax = false;
}
<|endoftext|>


<commit_before>// As explained here: http://code.google.com/p/phantomjs/wiki/QuickStart

var page = new WebPage(), address, output, size;
//console.log('Usage: rasterize.js URL filename');

var args = require('system').args;

// console.log(args[0]);
// console.log(args[1]);
// console.log(args[2]);
// console.log(args[3]);
// console.log(args[4]);

//var chinese_fonts = ['Microsoft yahei', 'Droid Sans Fallback', "宋体", "方正韵动中黑简体", "方正兰亭黑简体", "方正兰亭中黑_GBK", ".萍方-简"]
font = "'Helvetica','\\u65B9\\u6B63\\u5170\\u4EAD\\u4E2D\\u9ED1_GBK','Microsoft yahei','Segoe UI Symbol'";

var cookies = phantom.addCookie({
  'name': 'SUB',
  'domain': '.weibo.cn',
  'value': args[4],
  'path': '/'
});

address = args[1];
output = args[2];
page.viewportSize = {width: 880, height: 600};
page.zoomFactor = 2;

// http://phantomjs.org/api/webpage/handler/on-resource-requested.html
// page.onResourceRequested = function(requestData, networkRequest) {
//   //console.log('Request (#' + requestData.id + '): ' + JSON.stringify(requestData));
//   console.log(requestData.url);
//   if (requestData.url.indexOf('comment') != -1) {
//     //networkRequest.abort();
//     networkRequest.changeUrl("");
//   }
// };

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit();
    } else {
        console.log('Page loading status: ' + status);
        if (address.indexOf("comment") != -1) {
          window.setInterval(function() {
              page.evaluate(function() {
                // Scrolls to the bottom of page
                window.document.body.scrollTop = document.body.scrollHeight;
              });
          }, 10000);
        }

        window.setTimeout(function () {
            page.evaluate(function (font) {
                var r = /\\u([\d\w]{4})/gi;
                font = font.replace(r, function (match, grp) {
                        return String.fromCharCode(parseInt(grp, 16));});
                font = unescape(font);
                document.body.style["fontFamily"]=font;
            }, font);

            // page.evaluate(function() {
            //   var cmtTab = document.querySelectorAll('[cont-type="cmtTab"]')[0];
            //   if (cmtTab != null) {
            //     var ul = cmtTab.getElementsByTagName('ul');
            //     if (ul != null && ul.length > 1) {
            //         //ul[1].parentNode.removeChild(ul[1]);
            //         //ul[1].remove();
            //         ul[1].setAttribute('style', 'display:none');
            //     }
            //   }

            //   var cmtTab = document.querySelectorAll('[data-node-type="comment-list"]')[0];
            //   if (cmtTab != null) {
            //     var sec = cmtTab.getElementsByTagName('section');
            //     if (sec != null && sec.length > 1) {
            //         //sec[1].parentNode.removeChild(sec[1]);
            //         //sec[1].remove();
            //         sec[1].setAttribute('style', 'display:none');
            //     }
            //   }
            // });

            if (address.indexOf("comment") == -1) {
              var clipRect = page.evaluate(function(){
                var m1 = document.getElementsByClassName("module-infobox line-bottom more");
                if (m1.length != 0) return m1[0].getBoundingClientRect();

                var m2 = document.getElementsByClassName("commment-more");
                if (m2.length != 0) return m2[0].getBoundingClientRect();

                var m3 = document.getElementsByClassName("comment-more");
                if (m3.length != 0) return m3[0].getBoundingClientRect();

                return null;
              });

              if (clipRect != null) {
                page.clipRect = {
                  top: 0,
                  left: 0,
                  width: page.viewportSize['width'],
                  height: clipRect.top*page.zoomFactor + clipRect.height*page.zoomFactor*2
                };
              }
            }

            page.render(output);
            phantom.exit();
        }, args[3]);
    }
});<commit_msg>Update js script<commit_after>// As explained here: http://code.google.com/p/phantomjs/wiki/QuickStart

var page = new WebPage(), address, output;
//console.log('Usage: rasterize.js URL filename');

var args = require('system').args;

//var chinese_fonts = ['Microsoft yahei', 'Droid Sans Fallback', "宋体", "方正韵动中黑简体", "方正兰亭黑简体", "方正兰亭中黑_GBK", ".萍方-简"]
font = "'Helvetica','\\u65B9\\u6B63\\u5170\\u4EAD\\u4E2D\\u9ED1_GBK','Microsoft yahei','Segoe UI Symbol'";

var cookies = phantom.addCookie({
  'name': 'SUB',
  'domain': '.weibo.cn',
  'value': args[4],
  'path': '/'
});

address = args[1];
output = args[2];
page.viewportSize = {width: 880, height: 600};
page.zoomFactor = 2;

// http://phantomjs.org/api/webpage/handler/on-resource-requested.html
// page.onResourceRequested = function(requestData, networkRequest) {
//   //console.log('Request (#' + requestData.id + '): ' + JSON.stringify(requestData));
//   console.log(requestData.url);
//   if (requestData.url.indexOf('comment') != -1) {
//     //networkRequest.abort();
//     networkRequest.changeUrl("");
//   }
// };

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit();
    } else {
        console.log('Page loading status: ' + status);
        if (address.indexOf("comment") != -1) {
          window.setInterval(function() {
              page.evaluate(function() {
                // Scrolls to the bottom of page
                window.document.body.scrollTop = document.body.scrollHeight;
              });
          }, 10000);
        }

        window.setTimeout(function () {
            page.evaluate(function (font) {
                var r = /\\u([\d\w]{4})/gi;
                font = font.replace(r, function (match, grp) {
                        return String.fromCharCode(parseInt(grp, 16));});
                font = unescape(font);
                document.body.style["fontFamily"]=font;
            }, font);

            // page.evaluate(function() {
            //   var cmtTab = document.querySelectorAll('[cont-type="cmtTab"]')[0];
            //   if (cmtTab != null) {
            //     var ul = cmtTab.getElementsByTagName('ul');
            //     if (ul != null && ul.length > 1) {
            //         //ul[1].parentNode.removeChild(ul[1]);
            //         //ul[1].remove();
            //         ul[1].setAttribute('style', 'display:none');
            //     }
            //   }

            //   var cmtTab = document.querySelectorAll('[data-node-type="comment-list"]')[0];
            //   if (cmtTab != null) {
            //     var sec = cmtTab.getElementsByTagName('section');
            //     if (sec != null && sec.length > 1) {
            //         //sec[1].parentNode.removeChild(sec[1]);
            //         //sec[1].remove();
            //         sec[1].setAttribute('style', 'display:none');
            //     }
            //   }
            // });

            if (address.indexOf("comment") == -1) {
              var clipRect = page.evaluate(function(){
                var m1 = document.getElementsByClassName("module-infobox line-bottom more");
                if (m1.length != 0) return m1[0].getBoundingClientRect();

                var m2 = document.getElementsByClassName("commment-more");
                if (m2.length != 0) return m2[0].getBoundingClientRect();

                var m3 = document.getElementsByClassName("comment-more");
                if (m3.length != 0) return m3[0].getBoundingClientRect();

                return null;
              });

              if (clipRect != null) {
                page.clipRect = {
                  top: 0,
                  left: 0,
                  width: page.viewportSize['width'],
                  height: clipRect.top*page.zoomFactor + clipRect.height*page.zoomFactor*2
                };
              }
            }

            page.render(output);
            phantom.exit();
        }, args[3]);
    }
});<|endoftext|>


<commit_before>/**
* To disable set chLogDisabled = true in the calling context
* @function
*/
console.chLog = function (...args) {
    if (typeof chLogDisabled == 'undefined' || !chLogDisabled)
        console.log.apply(undefined, args);
}

/**
* To disable set chInfoDisabled = true in the calling context
* @function
*/
console.chInfo = function (...args) {
    if (typeof chInfoDisabled == 'undefined' || !chInfoDisabled)
        console.info.apply(undefined, args);
}

/**
* To disable set chWarnDisabled = true in the calling context
* @function
*/
console.chWarn = function (...args) {
    if (typeof chWarnDisabled == 'undefined' || !chWarnDisabled)
        console.warn.apply(undefined, args);
}

/**
* To disable set chErrorDisabled = true in the calling context
* @function
*/
console.chError = function (...args) {
    if (typeof chErrorDisabled == 'undefined' || !chErrorDisabled)
        console.error.apply(undefined, args);
}
<commit_msg>Logger implemented Not really a helper method, but insted a full replacement<commit_after>var CH = CH || {};

//you can have it all at once from here
//useful when you want to control all of your loggers from one place.
CH.Console = function () {
    this.logDisabled = false;
    this.infoDisabled = false;
    this.warnDisabled = false;
    this.errorDisabled = false;
};

CH.Console.prototype.log = function (...args) {
    if (!this.logDisabled) console.log.apply(undefined, args);
}

CH.Console.prototype.info = function (...args) {
    if (!this.infoDisabled) console.info.apply(undefined, args);
}

CH.Console.prototype.warn = function (...args) {
    if (!this.warnDisabled) console.warn.apply(undefined, args);
}

CH.Console.prototype.error = function (...args) {
    if (!this.errorDisabled) console.error.apply(undefined, args);
}

//you can have them one by one
//useful when you want it to be able to disable from one scope only alone
//without affecting any other log funcionality
CH.Console.Log = function () {
    this.disabled = false;
};
CH.Console.Log.prototype.log = CH.Console.prototype.log;

CH.Console.Info = function () {
    this.disabled = false;
};
CH.Console.Info.prototype.info = CH.Console.prototype.info;

CH.Console.Warn = function () {
    this.disabled = false;
};
CH.Console.Warn.prototype.warn = CH.Console.prototype.warn;

CH.Console.Error = function () {
    this.disabled = false;
};
CH.Console.Error.prototype.error = CH.Console.prototype.error;

<|endoftext|>


<commit_before>var equal = require('assert').equal,
  SandCastle = require('../lib').SandCastle;

exports.tests = {
  'on("exit") is fired when a sandboxed script calls the exit method': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
      exports.main = function() {\
        var result = 1 + 1;\
        exit({\
          results: [result]\
        });\
      }\
    ");

    script.on('exit', function(err, result) {
      equal(result.results[0], 2, prefix)
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'run() can have global variables passed into it': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
      exports.main = function() {\
        exit(foo);\
      }\
    ");

    script.on('exit', function(err, result) {
      equal('bar', result, prefix)
      sandcastle.kill();
      finished();
    });

    script.run({foo: 'bar'});
  },
  'require() cannot be called from sandbox': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
      exports.main = function() {\
        var net = require('net');\
      }\
    ");

    script.on('exit', function(err, result) {
      equal(err.message, 'require is not defined', prefix);
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'an API can be provided for untrusted JavaScript to interact with': function(finished, prefix) {
    var sandcastle = new SandCastle({
      api: './examples/api.js'
    });

    var script = sandcastle.createScript("\
      exports.main = function() {\
        getFact(function(fact) {\
          exit(fact);\
        });\
      }\
    ");

    script.on('exit', function(err, result) {
      equal(result, 'The rain in spain falls mostly on the plain.', prefix);
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'an API can be provided for untrusted JavaScript to interact with along with per-script API code': function(finished, prefix) {
    var sandcastle = new SandCastle({
      api: './examples/api.js'
    });

    var script = sandcastle.createScript("\
      exports.main = function() {\
        callAdditional(function(fact) {\
          exit(fact);\
        });\
      }\
    ", {extraAPI: "function anotherFunction(cb) { cb('The reign in spane falls mostly on the plain') }" });

    script.on('exit', function(err, result) {
      equal(result, 'The reign in spane falls mostly on the plain', prefix);
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'looping script should cause timeout event to be called and sandbox to respawn': function(finished, prefix) {
    var sandcastle = new SandCastle({
      api: './examples/api.js',
      timeout: 2000
    });

    var loopingScript = sandcastle.createScript("\
      exports.main = function() {\
        while(true) {};\
      }\
    ");

    var safeScript = sandcastle.createScript("\
      exports.main = function() {\
        exit('banana');\
      }\
    ");

    safeScript.on('exit', function(err, result) {
      equal(result, 'banana', prefix);
      sandcastle.kill();
      finished();
    });

    loopingScript.on('timeout', function() {
      safeScript.run();
    });

    loopingScript.run();
  },
  'sandbox should return a human readable stacktrace': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
        exports.main = function() {\n\
          var net = require('net');\n\
        }\n\
      "
    );

    script.on('exit', function(err, result) {
      equal(err.stack.indexOf('2:21') > -1, true, prefix);
      sandcastle.kill();
      finished();
    });
    script.run();
  },
  'enforce js-strict mode, when running scripts': function(finished, prefix) {
    var sandcastle = new SandCastle({useStrictMode: true});

    var script = sandcastle.createScript("\
        exports.main = function() {\n\
          globalObjectAccidentalPollution = true; \
          exit(0); \
        }\n\
      "
    );

    script.on('exit', function(err, result) {
      notEqual(-1, err.toString().indexOf("globalObjectAccidentalPollution is not defined"), prefix);
      sandcastle.kill();
      finished();
    });
    script.run();
  },
}<commit_msg>Added notEqual-function require.<commit_after>var equal = require('assert').equal,
    notEqual = require('assert').notEqual,
  SandCastle = require('../lib').SandCastle;

exports.tests = {
  'on("exit") is fired when a sandboxed script calls the exit method': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
      exports.main = function() {\
        var result = 1 + 1;\
        exit({\
          results: [result]\
        });\
      }\
    ");

    script.on('exit', function(err, result) {
      equal(result.results[0], 2, prefix)
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'run() can have global variables passed into it': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
      exports.main = function() {\
        exit(foo);\
      }\
    ");

    script.on('exit', function(err, result) {
      equal('bar', result, prefix)
      sandcastle.kill();
      finished();
    });

    script.run({foo: 'bar'});
  },
  'require() cannot be called from sandbox': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
      exports.main = function() {\
        var net = require('net');\
      }\
    ");

    script.on('exit', function(err, result) {
      equal(err.message, 'require is not defined', prefix);
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'an API can be provided for untrusted JavaScript to interact with': function(finished, prefix) {
    var sandcastle = new SandCastle({
      api: './examples/api.js'
    });

    var script = sandcastle.createScript("\
      exports.main = function() {\
        getFact(function(fact) {\
          exit(fact);\
        });\
      }\
    ");

    script.on('exit', function(err, result) {
      equal(result, 'The rain in spain falls mostly on the plain.', prefix);
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'an API can be provided for untrusted JavaScript to interact with along with per-script API code': function(finished, prefix) {
    var sandcastle = new SandCastle({
      api: './examples/api.js'
    });

    var script = sandcastle.createScript("\
      exports.main = function() {\
        callAdditional(function(fact) {\
          exit(fact);\
        });\
      }\
    ", {extraAPI: "function anotherFunction(cb) { cb('The reign in spane falls mostly on the plain') }" });

    script.on('exit', function(err, result) {
      equal(result, 'The reign in spane falls mostly on the plain', prefix);
      sandcastle.kill();
      finished();
    });

    script.run();
  },
  'looping script should cause timeout event to be called and sandbox to respawn': function(finished, prefix) {
    var sandcastle = new SandCastle({
      api: './examples/api.js',
      timeout: 2000
    });

    var loopingScript = sandcastle.createScript("\
      exports.main = function() {\
        while(true) {};\
      }\
    ");

    var safeScript = sandcastle.createScript("\
      exports.main = function() {\
        exit('banana');\
      }\
    ");

    safeScript.on('exit', function(err, result) {
      equal(result, 'banana', prefix);
      sandcastle.kill();
      finished();
    });

    loopingScript.on('timeout', function() {
      safeScript.run();
    });

    loopingScript.run();
  },
  'sandbox should return a human readable stacktrace': function(finished, prefix) {
    var sandcastle = new SandCastle();

    var script = sandcastle.createScript("\
        exports.main = function() {\n\
          var net = require('net');\n\
        }\n\
      "
    );

    script.on('exit', function(err, result) {
      equal(err.stack.indexOf('2:21') > -1, true, prefix);
      sandcastle.kill();
      finished();
    });
    script.run();
  },
  'enforce js-strict mode, when running scripts': function(finished, prefix) {
    var sandcastle = new SandCastle({useStrictMode: true});

    var script = sandcastle.createScript("\
        exports.main = function() {\n\
          globalObjectAccidentalPollution = true; \
          exit(0); \
        }\n\
      "
    );

    script.on('exit', function(err, result) {
      notEqual(-1, err.toString().indexOf("globalObjectAccidentalPollution is not defined"), prefix);
      sandcastle.kill();
      finished();
    });
    script.run();
  },
}<|endoftext|>


<commit_before>import expect from 'expect';
import expectJSX from 'expect-jsx';
expect.extend(expectJSX);

import React, { Component } from 'react';
import {render} from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import ScrollArea from '../src/js/ScrollArea';
import Scrollbar from '../src/js/Scrollbar';

function setup(props, sizes){
    let renderer = TestUtils.createRenderer();
    renderer.render(<ScrollArea {...props}>
content
</ScrollArea>);
    let instance = getRendererComponentInstance(renderer);

    if(sizes){
        instance.computeSizes = () => sizes
        instance.setSizesToState();
    }

    let output = renderer.getRenderOutput();

    let wrapper = output.props.children();

    let content = wrapper.props.children[0];
    let scrollbars = wrapper.props.children.filter(element => element && element.type == Scrollbar);

    return {
        wrapper,
        content,
        scrollbars,
        renderer,
        output,
        instance
    };
}

function setupComponentWithMockedSizes(props) {
    let component = setup(props, {
        realHeight: 300,
        containerHeight: 100,
        realWidth: 300,
        containerWidth: 100
    });

    return component;
}

function getRendererComponentInstance(renderer){
    return renderer._instance? renderer._instance._instance : null;
}

describe('ScrolLArea component', () => {
    it('Should render children and both scrollbars', () => {
        let {scrollbars, content} = setupComponentWithMockedSizes();

        expect(scrollbars.length).toBe(2);
        expect(content).toEqualJSX(

 {}}
                style={undefined}
                className="scrollarea-content "
                onTouchStart={() => {}}
                onTouchMove={() => {}}
                onTouchEnd={() => {}}>

content

);
    });

    it('Could render only vertical scrollbar', () => {
        let {scrollbars} = setupComponentWithMockedSizes({vertical: true, horizontal: false});
        let scrollbar = scrollbars[0];

        expect(scrollbars.length).toBe(1);
        expect(scrollbar.props.type).toBe('vertical');
    });

    it('Could render only horizontal scrollbar', () => {
        let {scrollbars} = setupComponentWithMockedSizes({vertical: false, horizontal: true});
        let scrollbar = scrollbars[0];

        expect(scrollbars.length).toBe(1);
        expect(scrollbar.props.type).toBe('horizontal');
    });

    it('Should change content element class when contentClassName porp is used', () => {
        let {content} = setup({contentClassName: 'test-class'});

        expect(content.props.className).toInclude('test-class');
    });

    it('Should have proper scrollbars styles', () => {
        let {content, scrollbars} = setupComponentWithMockedSizes({
            vertical: true,
            verticalScrollbarStyle: {test: 'verticalScrollbarStyle'},
            verticalContainerStyle: {test: 'verticalContainerStyle'},
            horizontal: true,
            horizontalScrollbarStyle: {test: 'horizontalScrollbarStyle'},
            horizontalContainerStyle: {test: 'horizontalContainerStyle'}
        });

        let verticalScrollbar = scrollbars.filter(component => component.props.type === 'vertical')[0];
        let horizontalScrollbar = scrollbars.filter(component => component.props.type === 'horizontal')[0];

        expect(verticalScrollbar.props.containerStyle).toEqual({test: 'verticalContainerStyle'});
        expect(verticalScrollbar.props.scrollbarStyle).toEqual({test: 'verticalScrollbarStyle'});
        expect(horizontalScrollbar.props.containerStyle).toEqual({test: 'horizontalContainerStyle'});
        expect(horizontalScrollbar.props.scrollbarStyle).toEqual({test: 'horizontalScrollbarStyle'});
    });

    it('normalizeTopPosition() shoud returns proper value', () => {
        let {    instance} = setup();
        let {normalizeTopPosition} = instance;
        let sizes = {realHeight: 30, containerHeight: 20};

        expect(normalizeTopPosition(0, sizes)).toBe(0);
        expect(normalizeTopPosition(5, sizes)).toBe(5);
        expect(normalizeTopPosition(10, sizes)).toBe(10);
        expect(normalizeTopPosition(11, sizes)).toBe(10);
        expect(normalizeTopPosition(-1, sizes)).toBe(0);
        expect(normalizeTopPosition(-60, sizes)).toBe(0);
        expect(normalizeTopPosition(100, sizes)).toBe(10);
    });

    it('normalizeLeftPosition() shoud returns proper value', () => {
        let {instance} = setup();
        let {normalizeLeftPosition} = instance;
        let sizes = {realWidth: 30, containerWidth: 20};

        expect(normalizeLeftPosition(0, sizes)).toBe(0);
        expect(normalizeLeftPosition(5, sizes)).toBe(5);
        expect(normalizeLeftPosition(10, sizes)).toBe(10);
        expect(normalizeLeftPosition(11, sizes)).toBe(10);
        expect(normalizeLeftPosition(-1, sizes)).toBe(0);
        expect(normalizeLeftPosition(-60, sizes)).toBe(0);
        expect(normalizeLeftPosition(100, sizes)).toBe(10);
    });

    it('handleWheel method work properly when scrolling down', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:20, deltaX: 0, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.topPosition).toBe(20);
    });

    it('handleWheel method work properly when scrolling up and actual topPosition is 0', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:-10, deltaX: 0, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.topPosition).toBe(0);
    });

    it('handleWheel method work properly when scrolling down more then content height', () => {
        let {instance} = setupComponentWithMockedSizes();

        for(let i = 0; i < 10; i++){
            let e = {deltaY:50, deltaX: 0, preventDefault: () => {}};
            instance.handleWheel(e);
        }

        expect(instance.state.topPosition).toBe(200);
    });

    it('handleWheel method work properly when scrolling right', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:0, deltaX: 20, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.leftPosition).toBe(20);
    });

    it('handleWheel method work properly when scrolling left and actual leftPosition is 0', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:0, deltaX: -10, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.leftPosition).toBe(0);
    });

    it('handleWheel method work properly when scrolling right more then content height', () => {
        let {instance} = setupComponentWithMockedSizes();

        for(let i = 0; i < 10; i++){
            let e = {deltaY:0, deltaX: 50, preventDefault: () => {}};
            instance.handleWheel(e);
        }

        expect(instance.state.leftPosition).toBe(200);
    });

    it('handleWheel method should scroll down on scrollRight wheel event when revertWheelAxes prop is set to true', () => {
        let {instance} = setupComponentWithMockedSizes({
            swapWheelAxes: true
        });

        let e = {deltaY:0, deltaX: 20, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.topPosition).toBe(20);
    });

    it('handleWheel method should scroll down on scrollRight wheel event when revertWheelAxes prop is set to true', () => {
        let {instance} = setupComponentWithMockedSizes({
            swapWheelAxes: true
        });

        let e = {deltaY:20, deltaX: 0, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.leftPosition).toBe(20);
    });

    it('scrollBottom() method should work when content is smaller then container', () => {
        let {instance} = setup({}, {
            realHeight: 30,
            containerHeight: 100,
            realWidth: 30,
            containerWidth: 100
        });

        instance.scrollBottom();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollBottom() method should scroll to bottom', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollBottom();
        expect(instance.state.topPosition).toBe(100);
    });

    it('scrollBottom() should be imposible when there is disabled vertical scroll', () => {
        let {instance} = setup({vertical: false}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollBottom();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollRight() method should work when content is smaller then container', () => {
        let {instance} = setup({}, {
            realHeight: 30,
            containerHeight: 100,
            realWidth: 30,
            containerWidth: 100
        });

        instance.scrollRight();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollRight() method should scroll to right', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollRight();
        expect(instance.state.leftPosition).toBe(100);
    });

    it('scrollRight() should be imposible when there is disabled horizontal scroll', () => {
        let {instance} = setup({horizontal: false}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollRight();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollLeft() method should scroll to left', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });
        instance.scrollXTo(50);

        instance.scrollLeft();
        expect(instance.state.leftPosition).toBe(0);
    });

    it('scrollTop() method should scroll to top', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });
        instance.scrollYTo(50);

        instance.scrollTop();
        expect(instance.state.topPosition).toBe(0);
    });
});
<commit_msg>fix tests<commit_after>import expect from 'expect';
import expectJSX from 'expect-jsx';
expect.extend(expectJSX);

import React, { Component } from 'react';
import {render} from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import ScrollArea from '../src/js/ScrollArea';
import Scrollbar from '../src/js/Scrollbar';

function setup(props, sizes){
    let renderer = TestUtils.createRenderer();
    renderer.render(<ScrollArea {...props}>
content
</ScrollArea>);
    let instance = getRendererComponentInstance(renderer);

    if(sizes){
        instance.computeSizes = () => sizes
        instance.setSizesToState();
    }

    let output = renderer.getRenderOutput();

    let wrapper = output.props.children();

    let content = wrapper.props.children[0];
    let scrollbars = wrapper.props.children.filter(element => element && element.type == Scrollbar);

    return {
        wrapper,
        content,
        scrollbars,
        renderer,
        output,
        instance
    };
}

function setupComponentWithMockedSizes(props) {
    let component = setup(props, {
        realHeight: 300,
        containerHeight: 100,
        realWidth: 300,
        containerWidth: 100
    });

    return component;
}

function getRendererComponentInstance(renderer){
    return renderer._instance? renderer._instance._instance : null;
}

describe('ScrolLArea component', () => {
    it('Should render children and both scrollbars', () => {
        let {scrollbars, content} = setupComponentWithMockedSizes();

        expect(scrollbars.length).toBe(2);
        expect(content).toEqualJSX(

 {}}
                style={undefined}
                className="scrollarea-content "
                onTouchStart={() => {}}
                onTouchMove={() => {}}
                onTouchEnd={() => {}}>

content

);
    });

    it('Could render only vertical scrollbar', () => {
        let {scrollbars} = setupComponentWithMockedSizes({vertical: true, horizontal: false});
        let scrollbar = scrollbars[0];

        expect(scrollbars.length).toBe(1);
        expect(scrollbar.props.type).toBe('vertical');
    });

    it('Could render only horizontal scrollbar', () => {
        let {scrollbars} = setupComponentWithMockedSizes({vertical: false, horizontal: true});
        let scrollbar = scrollbars[0];

        expect(scrollbars.length).toBe(1);
        expect(scrollbar.props.type).toBe('horizontal');
    });

    it('Should change content element class when contentClassName porp is used', () => {
        let {content} = setup({contentClassName: 'test-class'});

        expect(content.props.className).toInclude('test-class');
    });

    it('Should have proper scrollbars styles', () => {
        let {content, scrollbars} = setupComponentWithMockedSizes({
            vertical: true,
            verticalScrollbarStyle: {test: 'verticalScrollbarStyle'},
            verticalContainerStyle: {test: 'verticalContainerStyle'},
            horizontal: true,
            horizontalScrollbarStyle: {test: 'horizontalScrollbarStyle'},
            horizontalContainerStyle: {test: 'horizontalContainerStyle'}
        });

        let verticalScrollbar = scrollbars.filter(component => component.props.type === 'vertical')[0];
        let horizontalScrollbar = scrollbars.filter(component => component.props.type === 'horizontal')[0];

        expect(verticalScrollbar.props.containerStyle).toEqual({test: 'verticalContainerStyle'});
        expect(verticalScrollbar.props.scrollbarStyle).toEqual({test: 'verticalScrollbarStyle'});
        expect(horizontalScrollbar.props.containerStyle).toEqual({test: 'horizontalContainerStyle'});
        expect(horizontalScrollbar.props.scrollbarStyle).toEqual({test: 'horizontalScrollbarStyle'});
    });

    it('normalizeTopPosition() shoud returns proper value', () => {
        let {    instance} = setup();
        let {normalizeTopPosition} = instance;
        let sizes = {realHeight: 30, containerHeight: 20};

        expect(normalizeTopPosition(0, sizes)).toBe(0);
        expect(normalizeTopPosition(5, sizes)).toBe(5);
        expect(normalizeTopPosition(10, sizes)).toBe(10);
        expect(normalizeTopPosition(11, sizes)).toBe(10);
        expect(normalizeTopPosition(-1, sizes)).toBe(0);
        expect(normalizeTopPosition(-60, sizes)).toBe(0);
        expect(normalizeTopPosition(100, sizes)).toBe(10);
    });

    it('normalizeLeftPosition() shoud returns proper value', () => {
        let {instance} = setup();
        let {normalizeLeftPosition} = instance;
        let sizes = {realWidth: 30, containerWidth: 20};

        expect(normalizeLeftPosition(0, sizes)).toBe(0);
        expect(normalizeLeftPosition(5, sizes)).toBe(5);
        expect(normalizeLeftPosition(10, sizes)).toBe(10);
        expect(normalizeLeftPosition(11, sizes)).toBe(10);
        expect(normalizeLeftPosition(-1, sizes)).toBe(0);
        expect(normalizeLeftPosition(-60, sizes)).toBe(0);
        expect(normalizeLeftPosition(100, sizes)).toBe(10);
    });

    it('handleWheel method work properly when scrolling down', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:20, deltaX: 0, preventDefault: () => {}, stopPropagation: () => {}};
        instance.handleWheel(e);

        expect(instance.state.topPosition).toBe(20);
    });

    it('handleWheel method work properly when scrolling up and actual topPosition is 0', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:-10, deltaX: 0, preventDefault: () => {}};
        instance.handleWheel(e);

        expect(instance.state.topPosition).toBe(0);
    });

    it('handleWheel method work properly when scrolling down more then content height', () => {
        let {instance} = setupComponentWithMockedSizes();

        for(let i = 0; i < 10; i++){
            let e = {deltaY:50, deltaX: 0, preventDefault: () => {}, stopPropagation: () => {}};
            instance.handleWheel(e);
        }

        expect(instance.state.topPosition).toBe(200);
    });

    it('handleWheel method work properly when scrolling right', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:0, deltaX: 20, preventDefault: () => {}, stopPropagation: () => {}};
        instance.handleWheel(e);

        expect(instance.state.leftPosition).toBe(20);
    });

    it('handleWheel method work properly when scrolling left and actual leftPosition is 0', () => {
        let {instance} = setupComponentWithMockedSizes();
        let e = {deltaY:0, deltaX: -10, preventDefault: () => {}, stopPropagation: () => {}};
        instance.handleWheel(e);

        expect(instance.state.leftPosition).toBe(0);
    });

    it('handleWheel method work properly when scrolling right more then content height', () => {
        let {instance} = setupComponentWithMockedSizes();

        for(let i = 0; i < 10; i++){
            let e = {deltaY:0, deltaX: 50, preventDefault: () => {}, stopPropagation: () => {}};
            instance.handleWheel(e);
        }

        expect(instance.state.leftPosition).toBe(200);
    });

    it('handleWheel method should scroll down on scrollRight wheel event when revertWheelAxes prop is set to true', () => {
        let {instance} = setupComponentWithMockedSizes({
            swapWheelAxes: true
        });

        let e = {deltaY:0, deltaX: 20, preventDefault: () => {}, stopPropagation: () => {}};
        instance.handleWheel(e);

        expect(instance.state.topPosition).toBe(20);
    });

    it('handleWheel method should scroll down on scrollRight wheel event when revertWheelAxes prop is set to true', () => {
        let {instance} = setupComponentWithMockedSizes({
            swapWheelAxes: true
        });

        let e = {deltaY:20, deltaX: 0, preventDefault: () => {}, stopPropagation: () => {}};
        instance.handleWheel(e);

        expect(instance.state.leftPosition).toBe(20);
    });

    it('scrollBottom() method should work when content is smaller then container', () => {
        let {instance} = setup({}, {
            realHeight: 30,
            containerHeight: 100,
            realWidth: 30,
            containerWidth: 100
        });

        instance.scrollBottom();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollBottom() method should scroll to bottom', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollBottom();
        expect(instance.state.topPosition).toBe(100);
    });

    it('scrollBottom() should be imposible when there is disabled vertical scroll', () => {
        let {instance} = setup({vertical: false}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollBottom();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollRight() method should work when content is smaller then container', () => {
        let {instance} = setup({}, {
            realHeight: 30,
            containerHeight: 100,
            realWidth: 30,
            containerWidth: 100
        });

        instance.scrollRight();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollRight() method should scroll to right', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollRight();
        expect(instance.state.leftPosition).toBe(100);
    });

    it('scrollRight() should be imposible when there is disabled horizontal scroll', () => {
        let {instance} = setup({horizontal: false}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });

        instance.scrollRight();
        expect(instance.state.topPosition).toBe(0);
    });

    it('scrollLeft() method should scroll to left', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });
        instance.scrollXTo(50);

        instance.scrollLeft();
        expect(instance.state.leftPosition).toBe(0);
    });

    it('scrollTop() method should scroll to top', () => {
        let {instance} = setup({}, {
            realHeight: 200,
            containerHeight: 100,
            realWidth: 200,
            containerWidth: 100
        });
        instance.scrollYTo(50);

        instance.scrollTop();
        expect(instance.state.topPosition).toBe(0);
    });
});
<|endoftext|>