<commit_before>module.exports = function (categoryModule) {
    categoryModule

    .controller("categoryListControllerTheme", [
        "$scope",
        "$location",
        "$route",
        "$routeParams",
        "$categoryApiService",
        "$designService",
        "$designImageService",
        "$categoryService",
        "$visitorLoginService",
        "$cartService",
        "$pdpProductService",
        "$commonUtilService",
        "$q",
        "$timeout",
        "GENERAL_CATEGORY_URI",
        "SEARCH_KEY_NAME",
        function ($scope, $location, $route, $routeParams, $categoryApiService, $designService,
                  $designImageService, $categoryService, $visitorLoginService, $cartService,
                  $pdpProductService, $commonUtilService, $q, $timeout, GENERAL_CATEGORY_URI, SEARCH_KEY_NAME) {

            var init, getPage, addCategoryCrumbs, getFilters, setFilters, getParams, initWatchers,
                defaultFilterSet, defaultOptionSet, changeLocation, getShopPageProducts;

            getPage = function () {
                var param, page;

                page = 0;
                param = $location.search();

                if (typeof param.p !== "undefined") {
                    page = (param.p - 1);
                }

                return page;
            };

            addCategoryCrumbs = function () {

                if ($scope.isShop) {
                    $scope.$emit("add-breadcrumbs", {"label": "Shop", "url": $location.path()});
                } else {
                    var list, i, category;
                    list = $categoryService.getChainCategories($scope.categoryId);

                    for (i = 0; i < list.length; i += 1) {
                        category = list[i];
                        $scope.$emit("add-breadcrumbs", {"label": category.name, "url": $categoryService.getUrl(category.id)});
                    }
                }
            };

            getParams = function (withoutLimit) {
                var search, result, key;

                result = {};
                search = $location.search();

                for (key in search) {
                    if (search.hasOwnProperty(key)) {
                        result[key] = search[key];
                    }
                }

                if (!withoutLimit) {

                    if ($scope.currentPage === 0) {
                        result.limit = "0," + $scope.itemsPerPage;
                    } else {
                        result.limit = ($scope.currentPage * $scope.itemsPerPage) + "," + $scope.itemsPerPage;
                    }
                }

                return result;
            };

            init = function () {
                /**
                 * Variables for paginator
                 */
                $scope.currentPage = getPage();
                $scope.itemsPerPage = angular.appConfigValue("general.app.category.itemsPerPage");
                $scope.productsList = [];
                $scope.paths = [];
                $scope.isShop = (GENERAL_CATEGORY_URI === $location.path());
                $scope.categoryId = $routeParams.id || null;
                $scope.searchField = SEARCH_KEY_NAME;

                $scope.category = {
                    'banner': '/theme/images/category/shop.jpg'
                };

                $scope.popupProduct = {};
                $scope.productService = $pdpProductService;
                $scope.options = {};
                $scope.filters = {};
                $scope.blocks = {
                    "sort": false,
                    "search": false,
                    "filter": false
                };

                var getSearchText = function () {
                    $scope.searchText = "";
                    if (typeof $routeParams[$scope.searchField] !== "undefined") {
                        $scope.searchText = $routeParams[$scope.searchField].trim("~").replace(/,/g, " ");
                    }
                };
                getSearchText();

                addCategoryCrumbs();
            };
            init();

            changeLocation = function () {
                var filterStr, url;
                filterStr = getFilters();
                if (typeof filterStr !== "undefined") {
                    if ($scope.categoryId === null && $scope.isShop) {
                        url = GENERAL_CATEGORY_URI;
                    } else {
                        url = $categoryService.getUrl($scope.categoryId);
                    }

                    $categoryService.setFiltersInLocation(url, filterStr);
                }
            };

            initWatchers = function () {
                defaultFilterSet = $scope.$watch("filters", changeLocation, true);

                defaultOptionSet = $scope.$watch("options", function () {
                    $pdpProductService.setOptions($scope.options);
                    $scope.popupProduct = $pdpProductService.getProduct();
                }, true);
            };

            setFilters = function () {
                var params, values, i, initFilter;
                params = $location.search();
                initFilter = function (attr) {
                    if (typeof $scope.filters[attr] === "undefined") {
                        $scope.filters[attr] = {};
                    }
                };

                for (var attr in params) {

                    if (params.hasOwnProperty(attr)) {
                        initFilter(attr);

                        if (typeof params[attr] === "string") {
                            values = params[attr].replace(/[\?~]/, "").split(",");
                            for (i = 0; i < values.length; i += 1) {
                                $scope.filters[attr.replace(/[\?~]/, "")][values[i]] = true;
                            }
                        } else {
                            $scope.filters[attr.replace(/[\?~]/, "")][params[attr]] = true;
                        }

                    }

                }

            };

            setFilters();

            getFilters = function () {
                var filters, prepareFilters, hasFilter;
                filters = [];
                hasFilter = false;

                prepareFilters = function () {
                    var getFilterValues;

                    getFilterValues = function (attr) {
                        var values, val;
                        values = [];

                        for (val in $scope.filters[attr]) {
                            if ($scope.filters[attr].hasOwnProperty(val) &&
                                $scope.filters[attr][val] === true) {
                                values.push(val);
                                hasFilter = true;
                            }
                        }

                        return values;
                    };
                    for (var attr in $scope.filters) {
                        if ($scope.filters.hasOwnProperty(attr)) {
                            var values = getFilterValues(attr);
                            if (values.length > 0 && attr !== SEARCH_KEY_NAME) {
                                filters.push(attr + "=" + values.join(","));
                            } else if (values.length > 0 && attr === SEARCH_KEY_NAME && values.join(",") !== "") {
                                filters.push(attr + "=~" + values.join(","));
                            }
                        }
                    }
                };

                prepareFilters();

                if (!hasFilter) {
                    return "";
                }

                return filters.join("&");
            };

            // KG homepage shows products separated by category
            getShopPageProducts = function (categories) {
                if ($scope.isShop && categories.length) {

                    var params = getParams();
                    var productsPromise = [];
                    var shopCategories = [];

                    // Get thr product from each of the categories
                    $.each(categories[0].child, function (i, cat) {
                        shopCategories.push(cat);
                        params['categoryID'] = cat.id;

                        productsPromise.push(
                            $categoryApiService.getProductsByCategoryId(params)
                                .$promise.then(function (response) {
                                    response.id = cat.id;
                                    return response;
                                })
                        );
                    });

                    // When they all finish, assemble a response
                    $q.all(productsPromise).then(function (result) {
                        $.each(result, function (i, cat) {
                            $.each(shopCategories, function (j, outCat) {
                                if (outCat.id == cat.id) {
                                    shopCategories[j]['productList'] = cat.result;
                                    return false; //break
                                }
                            });
                        });

                        $scope.shopCategories = shopCategories;

                    });
                }
            };

            /**
             * Gets number items into collection
             */
            $scope.getCountProduct = function () {
                if ($scope.isShop) {
                    $categoryApiService.getShopCountProducts(getParams(true)).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.totalItems = result;
                        $scope.pages = Math.ceil($scope.totalItems / $scope.itemsPerPage);
                    });
                } else {
                    var params = getParams(true);
                    params["categoryID"] = $scope.categoryId;
                    $categoryApiService.getCountProducts(params).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.totalItems = result;
                        $scope.pages = Math.ceil($scope.totalItems / $scope.itemsPerPage);
                    });
                }

            };

            /**
             * Gets list of products
             */
            $scope.getProducts = function () {
                if ($scope.isShop) {
                    var categories = $categoryService.getTree();
                    if (categories) {
                        getShopPageProducts(categories);
                    }

                    // KG /shop is dependent on the category tree
                    // $categoryApiService.getShopProducts(getParams(), {}).$promise.then(function (response) {
                    //     var result = response.result || [];
                    //     $scope.productsList = result;
                    // });

                } else {
                    var params = getParams();
                    params["categoryID"] = $scope.categoryId;
                    $categoryApiService.getProductsByCategoryId(params).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.productsList = result;
                    });
                }
            };

            /**
             * Gets layers for category
             */
            $scope.getLayered = function () {
                if ($scope.isShop) {
                    $categoryApiService.getShopLayered($location.search(), {}).$promise.then(function (response) {
                            var result = response.result || [];
                            $scope.layered = result;
                            for (var filter in $scope.layered) {
                                if ($scope.layered.hasOwnProperty(filter)) {
                                    $scope.filters[filter] = {};
                                }
                            }
                            setFilters();
                        }
                    );
                } else {
                    var params = $location.search();
                    params["categoryID"] = $scope.categoryId;
                    $categoryApiService.getLayered(params).$promise.then(function (response) {
                            var result = response.result || [];
                            $scope.layered = result;
                            for (var filter in $scope.layered) {
                                if ($scope.layered.hasOwnProperty(filter)) {
                                    $scope.filters[filter] = {};
                                }
                            }
                            setFilters();
                        }
                    );
                }
            };

            $scope.init = function () {
                var tree;

                tree = $categoryService.getTree();
                if (typeof tree === "undefined") {
                    $categoryApiService.getCategories().$promise.then(
                        function (response) {
                            var categories = response.result || [];
                            $categoryService.setTree(categories);
                            addCategoryCrumbs();
                            return categories;
                        }
                    )
                        .then( getShopPageProducts );
                }
                $scope.getLayered();
                $scope.getProducts();
                $scope.getCountProduct();

                if ($scope.categoryId !== null) {

                    $categoryApiService.load({"id": $scope.categoryId}).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.category = result;

                        var categoryImages = {
                            'default': '/theme/images/category/shop.jpg',
                            '5512f069d4a2560a14000036': '/theme/images/category/shop.jpg',
                            // '5512f195d4a2560a14000074': 'skin-care',
                            '5512f1cdd4a2560a14000082': '/theme/images/category/lip-treatment.jpg',
                            '5512f248d4a2560a14000094': '/theme/images/category/makeup.jpg',
                            // '': 'gifts'
                        };

                        $scope.category.banner = categoryImages[$scope.categoryId] || categoryImages.default;
                    });
                }

                initWatchers();
            };

            $scope.toggleBlock = function (activeBlock) {
                var block;

                for (block in $scope.blocks) {

                    if ($scope.blocks.hasOwnProperty(block)) {
                        if (block === activeBlock) {
                            if ($scope.blocks[block]) {
                                $scope.blocks[block] = false;
                            } else {
                                $scope.blocks[block] = true;
                            }
                        } else {
                            $scope.blocks[block] = false;
                        }
                    }

                }

                return true;
            };

            $scope.closeBlock = function (nameBlock) {
                $scope.blocks[nameBlock] = false;
                jQuery('.list-bar span').removeClass('active');
                jQuery('.shadow').css('display', 'none');
            };

            $scope.viewDetails = function (product) {

                //TODO: we should get away from touching the dom in the
                // controllers
                $("#quick-view").modal('hide');
                $timeout(function() {
                    var url = $pdpProductService.getUrl(product._id);
                    $location.path(url);
                }, 250);
            }

            $scope.addToCart = function (product) {
                var miniCart, addItem;
                miniCart = $(".mini-cart");
                addItem = function () {
                    $cartService.add(product._id, 1, $pdpProductService.getOptions()).then(
                        function (response) {
                            if (response.error !== null) {
                                $scope.openPopUp(product);
                                $scope.message = $commonUtilService.getMessage(response);
                            } else {
                                $pdpProductService.setOptions({});
                                $("#quick-view").modal('hide');

                                miniCart.modal('show');

                                //TODO: cleanup
                                setTimeout(function () {
                                    miniCart.modal('hide');
                                }, 2000);
                            }
                        }
                    );
                };

                if (angular.appConfigValue("general.checkout.guest_checkout")) {
                    addItem();
                } else {
                    $visitorLoginService.isLoggedIn().then(function (isLoggedIn) {
                        if (isLoggedIn) {
                            addItem();
                        } else {
                            $("#form-login").modal("show");
                        }
                    });
                }

            };

            /**
             * Gets full path to image
             *
             * @param {object} product
             * @returns {string}
             */
            $scope.getImage = function (product, size) {
                if (typeof product === "undefined") {
                    return $designImageService.getFullImagePath("", null, size);
                }
                return $designImageService.getFullImagePath("", product["default_image"], size);
            };

            $scope.sortByPrice = function (order) {
                var orderStr;

                if (order === "asc") {
                    orderStr = "price";
                } else {
                    orderStr = "^price";
                }

                $scope.filters.sort = {};
                $scope.filters.sort[orderStr] = true;
            };

            $scope.sortByName = function (order) {
                var orderStr;

                if (order === "asc") {
                    orderStr = "name";
                } else {
                    orderStr = "^name";
                }

                $scope.filters.sort = {};
                $scope.filters.sort[orderStr] = true;
            };

            $scope.openPopUp = function (product) {
                $scope.message = {};
                $scope.options = {};
                $pdpProductService.setProduct(product);
                $scope.popupProduct = $pdpProductService.getProduct();
                $scope.productService.getRatingInfo(product._id);
                $("#quick-view").modal('show');
                setTimeout(function () {
                    try {
                        $('.rating').rating('update', $scope.productService.getAverageRating());
                    } catch (e) {

                    }
                }, 300);
            };

            $scope.showMoreBtn = function () {
                var countLoadedGoods;
                countLoadedGoods = ($scope.currentPage + 1) * $scope.itemsPerPage;

                if (countLoadedGoods >= $scope.totalItems) {
                    return false;
                }

                return true;
            };

            $scope.loadMore = function () {
                $scope.clickMore = true;
                $scope.currentPage += 1;

                var params = getParams();
                params["categoryID"] = $scope.categoryId;

                $categoryApiService.getProductsByCategoryId(params).$promise.then(
                    function (response) {
                        var result = response.result || [];
                        $scope.productsList = $scope.productsList.concat(result);
                    }
                );
                if ($scope.isShop) {
                    $categoryApiService.getShopProducts(params).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.productsList = $scope.productsList.concat(result);
                    });
                } else {
                    $categoryApiService.getProductsByCategoryId(params).$promise.then(
                        function (response) {
                            var result = response.result || [];
                            $scope.productsList = $scope.productsList.concat(result);
                        }
                    );
                }
            };

            $scope.search = function () {
                var searchObj, values;
                searchObj = {};
                values = this.searchText.split(/[, ]/);
                searchObj[$scope.searchField] = {};
                for (var i = 0; i < values.length; i += 1) {
                    searchObj[$scope.searchField][values[i]] = true;
                }
                $scope.filters[$scope.searchField] = searchObj[$scope.searchField];
            };
        }
    ]);
};
<commit_msg>move banner default so we don't see a flash<commit_after>module.exports = function (categoryModule) {
    categoryModule

    .controller("categoryListControllerTheme", [
        "$scope",
        "$location",
        "$route",
        "$routeParams",
        "$categoryApiService",
        "$designService",
        "$designImageService",
        "$categoryService",
        "$visitorLoginService",
        "$cartService",
        "$pdpProductService",
        "$commonUtilService",
        "$q",
        "$timeout",
        "GENERAL_CATEGORY_URI",
        "SEARCH_KEY_NAME",
        function ($scope, $location, $route, $routeParams, $categoryApiService, $designService,
                  $designImageService, $categoryService, $visitorLoginService, $cartService,
                  $pdpProductService, $commonUtilService, $q, $timeout, GENERAL_CATEGORY_URI, SEARCH_KEY_NAME) {

            var init, getPage, addCategoryCrumbs, getFilters, setFilters, getParams, initWatchers,
                defaultFilterSet, defaultOptionSet, changeLocation, getShopPageProducts;

            getPage = function () {
                var param, page;

                page = 0;
                param = $location.search();

                if (typeof param.p !== "undefined") {
                    page = (param.p - 1);
                }

                return page;
            };

            addCategoryCrumbs = function () {

                if ($scope.isShop) {
                    $scope.$emit("add-breadcrumbs", {"label": "Shop", "url": $location.path()});
                } else {
                    var list, i, category;
                    list = $categoryService.getChainCategories($scope.categoryId);

                    for (i = 0; i < list.length; i += 1) {
                        category = list[i];
                        $scope.$emit("add-breadcrumbs", {"label": category.name, "url": $categoryService.getUrl(category.id)});
                    }
                }
            };

            getParams = function (withoutLimit) {
                var search, result, key;

                result = {};
                search = $location.search();

                for (key in search) {
                    if (search.hasOwnProperty(key)) {
                        result[key] = search[key];
                    }
                }

                if (!withoutLimit) {

                    if ($scope.currentPage === 0) {
                        result.limit = "0," + $scope.itemsPerPage;
                    } else {
                        result.limit = ($scope.currentPage * $scope.itemsPerPage) + "," + $scope.itemsPerPage;
                    }
                }

                return result;
            };

            init = function () {
                /**
                 * Variables for paginator
                 */
                $scope.currentPage = getPage();
                $scope.itemsPerPage = angular.appConfigValue("general.app.category.itemsPerPage");
                $scope.productsList = [];
                $scope.paths = [];
                $scope.isShop = (GENERAL_CATEGORY_URI === $location.path());
                $scope.categoryId = $routeParams.id || null;
                $scope.searchField = SEARCH_KEY_NAME;

                $scope.category = {};
                $scope.popupProduct = {};
                $scope.productService = $pdpProductService;
                $scope.options = {};
                $scope.filters = {};
                $scope.blocks = {
                    "sort": false,
                    "search": false,
                    "filter": false
                };

                var getSearchText = function () {
                    $scope.searchText = "";
                    if (typeof $routeParams[$scope.searchField] !== "undefined") {
                        $scope.searchText = $routeParams[$scope.searchField].trim("~").replace(/,/g, " ");
                    }
                };
                getSearchText();

                addCategoryCrumbs();
            };
            init();

            changeLocation = function () {
                var filterStr, url;
                filterStr = getFilters();
                if (typeof filterStr !== "undefined") {
                    if ($scope.categoryId === null && $scope.isShop) {
                        url = GENERAL_CATEGORY_URI;
                    } else {
                        url = $categoryService.getUrl($scope.categoryId);
                    }

                    $categoryService.setFiltersInLocation(url, filterStr);
                }
            };

            initWatchers = function () {
                defaultFilterSet = $scope.$watch("filters", changeLocation, true);

                defaultOptionSet = $scope.$watch("options", function () {
                    $pdpProductService.setOptions($scope.options);
                    $scope.popupProduct = $pdpProductService.getProduct();
                }, true);
            };

            setFilters = function () {
                var params, values, i, initFilter;
                params = $location.search();
                initFilter = function (attr) {
                    if (typeof $scope.filters[attr] === "undefined") {
                        $scope.filters[attr] = {};
                    }
                };

                for (var attr in params) {

                    if (params.hasOwnProperty(attr)) {
                        initFilter(attr);

                        if (typeof params[attr] === "string") {
                            values = params[attr].replace(/[\?~]/, "").split(",");
                            for (i = 0; i < values.length; i += 1) {
                                $scope.filters[attr.replace(/[\?~]/, "")][values[i]] = true;
                            }
                        } else {
                            $scope.filters[attr.replace(/[\?~]/, "")][params[attr]] = true;
                        }

                    }

                }

            };

            setFilters();

            getFilters = function () {
                var filters, prepareFilters, hasFilter;
                filters = [];
                hasFilter = false;

                prepareFilters = function () {
                    var getFilterValues;

                    getFilterValues = function (attr) {
                        var values, val;
                        values = [];

                        for (val in $scope.filters[attr]) {
                            if ($scope.filters[attr].hasOwnProperty(val) &&
                                $scope.filters[attr][val] === true) {
                                values.push(val);
                                hasFilter = true;
                            }
                        }

                        return values;
                    };
                    for (var attr in $scope.filters) {
                        if ($scope.filters.hasOwnProperty(attr)) {
                            var values = getFilterValues(attr);
                            if (values.length > 0 && attr !== SEARCH_KEY_NAME) {
                                filters.push(attr + "=" + values.join(","));
                            } else if (values.length > 0 && attr === SEARCH_KEY_NAME && values.join(",") !== "") {
                                filters.push(attr + "=~" + values.join(","));
                            }
                        }
                    }
                };

                prepareFilters();

                if (!hasFilter) {
                    return "";
                }

                return filters.join("&");
            };

            // KG homepage shows products separated by category
            getShopPageProducts = function (categories) {
                if ($scope.isShop && categories.length) {

                    var params = getParams();
                    var productsPromise = [];
                    var shopCategories = [];

                    // Get thr product from each of the categories
                    $.each(categories[0].child, function (i, cat) {
                        shopCategories.push(cat);
                        params['categoryID'] = cat.id;

                        productsPromise.push(
                            $categoryApiService.getProductsByCategoryId(params)
                                .$promise.then(function (response) {
                                    response.id = cat.id;
                                    return response;
                                })
                        );
                    });

                    // When they all finish, assemble a response
                    $q.all(productsPromise).then(function (result) {
                        $.each(result, function (i, cat) {
                            $.each(shopCategories, function (j, outCat) {
                                if (outCat.id == cat.id) {
                                    shopCategories[j]['productList'] = cat.result;
                                    return false; //break
                                }
                            });
                        });

                        $scope.shopCategories = shopCategories;

                    });
                }
            };

            /**
             * Gets number items into collection
             */
            $scope.getCountProduct = function () {
                if ($scope.isShop) {
                    $categoryApiService.getShopCountProducts(getParams(true)).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.totalItems = result;
                        $scope.pages = Math.ceil($scope.totalItems / $scope.itemsPerPage);
                    });
                } else {
                    var params = getParams(true);
                    params["categoryID"] = $scope.categoryId;
                    $categoryApiService.getCountProducts(params).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.totalItems = result;
                        $scope.pages = Math.ceil($scope.totalItems / $scope.itemsPerPage);
                    });
                }

            };

            /**
             * Gets list of products
             */
            $scope.getProducts = function () {
                if ($scope.isShop) {
                    var categories = $categoryService.getTree();
                    if (categories) {
                        getShopPageProducts(categories);
                    }

                    // KG /shop is dependent on the category tree
                    // $categoryApiService.getShopProducts(getParams(), {}).$promise.then(function (response) {
                    //     var result = response.result || [];
                    //     $scope.productsList = result;
                    // });

                } else {
                    var params = getParams();
                    params["categoryID"] = $scope.categoryId;
                    $categoryApiService.getProductsByCategoryId(params).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.productsList = result;
                    });
                }
            };

            /**
             * Gets layers for category
             */
            $scope.getLayered = function () {
                if ($scope.isShop) {
                    $categoryApiService.getShopLayered($location.search(), {}).$promise.then(function (response) {
                            var result = response.result || [];
                            $scope.layered = result;
                            for (var filter in $scope.layered) {
                                if ($scope.layered.hasOwnProperty(filter)) {
                                    $scope.filters[filter] = {};
                                }
                            }
                            setFilters();
                        }
                    );
                } else {
                    var params = $location.search();
                    params["categoryID"] = $scope.categoryId;
                    $categoryApiService.getLayered(params).$promise.then(function (response) {
                            var result = response.result || [];
                            $scope.layered = result;
                            for (var filter in $scope.layered) {
                                if ($scope.layered.hasOwnProperty(filter)) {
                                    $scope.filters[filter] = {};
                                }
                            }
                            setFilters();
                        }
                    );
                }
            };

            $scope.init = function () {
                var tree;

                tree = $categoryService.getTree();
                if (typeof tree === "undefined") {
                    $categoryApiService.getCategories().$promise.then(
                        function (response) {
                            var categories = response.result || [];
                            $categoryService.setTree(categories);
                            addCategoryCrumbs();
                            return categories;
                        }
                    )
                        .then( getShopPageProducts );
                }
                $scope.getLayered();
                $scope.getProducts();
                $scope.getCountProduct();

                if ($scope.categoryId !== null) {

                    $categoryApiService.load({"id": $scope.categoryId}).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.category = result;

                        var categoryImages = {
                            'default': '/theme/images/category/shop.jpg',
                            '5512f069d4a2560a14000036': '/theme/images/category/shop.jpg',
                            // '5512f195d4a2560a14000074': 'skin-care',
                            '5512f1cdd4a2560a14000082': '/theme/images/category/lip-treatment.jpg',
                            '5512f248d4a2560a14000094': '/theme/images/category/makeup.jpg',
                            // '': 'gifts'
                        };

                        $scope.category.banner = categoryImages[$scope.categoryId] || categoryImages.default;
                    });
                } else {
                    $scope.category.banner = '/theme/images/category/shop.jpg';
                }

                initWatchers();
            };

            $scope.toggleBlock = function (activeBlock) {
                var block;

                for (block in $scope.blocks) {

                    if ($scope.blocks.hasOwnProperty(block)) {
                        if (block === activeBlock) {
                            if ($scope.blocks[block]) {
                                $scope.blocks[block] = false;
                            } else {
                                $scope.blocks[block] = true;
                            }
                        } else {
                            $scope.blocks[block] = false;
                        }
                    }

                }

                return true;
            };

            $scope.closeBlock = function (nameBlock) {
                $scope.blocks[nameBlock] = false;
                jQuery('.list-bar span').removeClass('active');
                jQuery('.shadow').css('display', 'none');
            };

            $scope.viewDetails = function (product) {

                //TODO: we should get away from touching the dom in the
                // controllers
                $("#quick-view").modal('hide');
                $timeout(function() {
                    var url = $pdpProductService.getUrl(product._id);
                    $location.path(url);
                }, 250);
            }

            $scope.addToCart = function (product) {
                var miniCart, addItem;
                miniCart = $(".mini-cart");
                addItem = function () {
                    $cartService.add(product._id, 1, $pdpProductService.getOptions()).then(
                        function (response) {
                            if (response.error !== null) {
                                $scope.openPopUp(product);
                                $scope.message = $commonUtilService.getMessage(response);
                            } else {
                                $pdpProductService.setOptions({});
                                $("#quick-view").modal('hide');

                                miniCart.modal('show');

                                //TODO: cleanup
                                setTimeout(function () {
                                    miniCart.modal('hide');
                                }, 2000);
                            }
                        }
                    );
                };

                if (angular.appConfigValue("general.checkout.guest_checkout")) {
                    addItem();
                } else {
                    $visitorLoginService.isLoggedIn().then(function (isLoggedIn) {
                        if (isLoggedIn) {
                            addItem();
                        } else {
                            $("#form-login").modal("show");
                        }
                    });
                }

            };

            /**
             * Gets full path to image
             *
             * @param {object} product
             * @returns {string}
             */
            $scope.getImage = function (product, size) {
                if (typeof product === "undefined") {
                    return $designImageService.getFullImagePath("", null, size);
                }
                return $designImageService.getFullImagePath("", product["default_image"], size);
            };

            $scope.sortByPrice = function (order) {
                var orderStr;

                if (order === "asc") {
                    orderStr = "price";
                } else {
                    orderStr = "^price";
                }

                $scope.filters.sort = {};
                $scope.filters.sort[orderStr] = true;
            };

            $scope.sortByName = function (order) {
                var orderStr;

                if (order === "asc") {
                    orderStr = "name";
                } else {
                    orderStr = "^name";
                }

                $scope.filters.sort = {};
                $scope.filters.sort[orderStr] = true;
            };

            $scope.openPopUp = function (product) {
                $scope.message = {};
                $scope.options = {};
                $pdpProductService.setProduct(product);
                $scope.popupProduct = $pdpProductService.getProduct();
                $scope.productService.getRatingInfo(product._id);
                $("#quick-view").modal('show');
                setTimeout(function () {
                    try {
                        $('.rating').rating('update', $scope.productService.getAverageRating());
                    } catch (e) {

                    }
                }, 300);
            };

            $scope.showMoreBtn = function () {
                var countLoadedGoods;
                countLoadedGoods = ($scope.currentPage + 1) * $scope.itemsPerPage;

                if (countLoadedGoods >= $scope.totalItems) {
                    return false;
                }

                return true;
            };

            $scope.loadMore = function () {
                $scope.clickMore = true;
                $scope.currentPage += 1;

                var params = getParams();
                params["categoryID"] = $scope.categoryId;

                $categoryApiService.getProductsByCategoryId(params).$promise.then(
                    function (response) {
                        var result = response.result || [];
                        $scope.productsList = $scope.productsList.concat(result);
                    }
                );
                if ($scope.isShop) {
                    $categoryApiService.getShopProducts(params).$promise.then(function (response) {
                        var result = response.result || [];
                        $scope.productsList = $scope.productsList.concat(result);
                    });
                } else {
                    $categoryApiService.getProductsByCategoryId(params).$promise.then(
                        function (response) {
                            var result = response.result || [];
                            $scope.productsList = $scope.productsList.concat(result);
                        }
                    );
                }
            };

            $scope.search = function () {
                var searchObj, values;
                searchObj = {};
                values = this.searchText.split(/[, ]/);
                searchObj[$scope.searchField] = {};
                for (var i = 0; i < values.length; i += 1) {
                    searchObj[$scope.searchField][values[i]] = true;
                }
                $scope.filters[$scope.searchField] = searchObj[$scope.searchField];
            };
        }
    ]);
};
<|endoftext|>


<commit_before>System.config({
  defaultJSExtensions: true,
  transpiler: "babel",
  babelOptions: {
    "optional": [
      "es7.decorators",
      "es7.classProperties"
    ]
  },
  paths: {
    "*": "src/*",
    "github:*": "jspm_packages/github/*",
    "npm:*": "jspm_packages/npm/*"
  },

  map: {
    "aurelia-animator-css": "npm:aurelia-animator-css@1.0.0-beta.1.0.1",
    "aurelia-bootstrapper": "npm:aurelia-bootstrapper@1.0.0-beta.1",
    "aurelia-fetch-client": "npm:aurelia-fetch-client@1.0.0-beta.1",
    "aurelia-framework": "npm:aurelia-framework@1.0.0-beta.1",
    "aurelia-history-browser": "npm:aurelia-history-browser@1.0.0-beta.1",
    "aurelia-html-import-template-loader": "npm:aurelia-html-import-template-loader@1.0.0-beta.1.0.1",
    "aurelia-loader-default": "npm:aurelia-loader-default@1.0.0-beta.1.0.1",
    "aurelia-logging-console": "npm:aurelia-logging-console@1.0.0-beta.1",
    "aurelia-polymer": "github:roguePanda/aurelia-polymer@0.2.1",
    "aurelia-router": "npm:aurelia-router@1.0.0-beta.1",
    "aurelia-templating-binding": "npm:aurelia-templating-binding@1.0.0-beta.1",
    "aurelia-templating-resources": "npm:aurelia-templating-resources@1.0.0-beta.1.0.1",
    "aurelia-templating-router": "npm:aurelia-templating-router@1.0.0-beta.1.0.1",
    "babel": "npm:babel-core@5.8.34",
    "babel-runtime": "npm:babel-runtime@5.8.34",
    "bootstrap": "github:twbs/bootstrap@3.3.5",
    "core-js": "npm:core-js@1.2.6",
    "fetch": "github:github/fetch@0.10.1",
    "font-awesome": "npm:font-awesome@4.4.0",
    "text": "github:systemjs/plugin-text@0.0.3",
    "github:jspm/nodelibs-assert@0.1.0": {
      "assert": "npm:assert@1.3.0"
    },
    "github:jspm/nodelibs-path@0.1.0": {
      "path-browserify": "npm:path-browserify@0.0.0"
    },
    "github:jspm/nodelibs-process@0.1.2": {
      "process": "npm:process@0.11.2"
    },
    "github:jspm/nodelibs-util@0.1.0": {
      "util": "npm:util@0.10.3"
    },
    "github:twbs/bootstrap@3.3.5": {
      "jquery": "github:components/jquery@2.1.4"
    },
    "npm:assert@1.3.0": {
      "util": "npm:util@0.10.3"
    },
    "npm:aurelia-animator-css@1.0.0-beta.1.0.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1"
    },
    "npm:aurelia-binding@1.0.0-beta.1.0.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-bootstrapper@1.0.0-beta.1": {
      "aurelia-event-aggregator": "npm:aurelia-event-aggregator@1.0.0-beta.1",
      "aurelia-framework": "npm:aurelia-framework@1.0.0-beta.1",
      "aurelia-history": "npm:aurelia-history@1.0.0-beta.1",
      "aurelia-history-browser": "npm:aurelia-history-browser@1.0.0-beta.1",
      "aurelia-loader-default": "npm:aurelia-loader-default@1.0.0-beta.1.0.1",
      "aurelia-logging-console": "npm:aurelia-logging-console@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-pal-browser": "npm:aurelia-pal-browser@1.0.0-beta.1",
      "aurelia-router": "npm:aurelia-router@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1",
      "aurelia-templating-binding": "npm:aurelia-templating-binding@1.0.0-beta.1",
      "aurelia-templating-resources": "npm:aurelia-templating-resources@1.0.0-beta.1.0.1",
      "aurelia-templating-router": "npm:aurelia-templating-router@1.0.0-beta.1.0.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-dependency-injection@1.0.0-beta.1": {
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-event-aggregator@1.0.0-beta.1": {
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1"
    },
    "npm:aurelia-fetch-client@1.0.0-beta.1": {
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-framework@1.0.0-beta.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-history-browser@1.0.0-beta.1": {
      "aurelia-history": "npm:aurelia-history@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-html-import-template-loader@1.0.0-beta.1.0.1": {
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1.0.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1.0.2",
      "webcomponentsjs": "github:webcomponents/webcomponentsjs@0.7.20"
    },
    "npm:aurelia-loader-default@1.0.0-beta.1.0.1": {
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-loader@1.0.0-beta.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1"
    },
    "npm:aurelia-loader@1.0.0-beta.1.0.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1"
    },
    "npm:aurelia-logging-console@1.0.0-beta.1": {
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-metadata@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1.0.2",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-pal-browser@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-route-recognizer@1.0.0-beta.1": {
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-router@1.0.0-beta.1": {
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-event-aggregator": "npm:aurelia-event-aggregator@1.0.0-beta.1",
      "aurelia-history": "npm:aurelia-history@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-route-recognizer": "npm:aurelia-route-recognizer@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-task-queue@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-templating-binding@1.0.0-beta.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1"
    },
    "npm:aurelia-templating-resources@1.0.0-beta.1.0.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-templating-router@1.0.0-beta.1.0.1": {
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-router": "npm:aurelia-router@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1"
    },
    "npm:aurelia-templating@1.0.0-beta.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:babel-runtime@5.8.34": {
      "process": "github:jspm/nodelibs-process@0.1.2"
    },
    "npm:core-js@1.2.6": {
      "fs": "github:jspm/nodelibs-fs@0.1.2",
      "path": "github:jspm/nodelibs-path@0.1.0",
      "process": "github:jspm/nodelibs-process@0.1.2",
      "systemjs-json": "github:systemjs/plugin-json@0.1.0"
    },
    "npm:font-awesome@4.4.0": {
      "css": "github:systemjs/plugin-css@0.1.19"
    },
    "npm:inherits@2.0.1": {
      "util": "github:jspm/nodelibs-util@0.1.0"
    },
    "npm:path-browserify@0.0.0": {
      "process": "github:jspm/nodelibs-process@0.1.2"
    },
    "npm:process@0.11.2": {
      "assert": "github:jspm/nodelibs-assert@0.1.0"
    },
    "npm:util@0.10.3": {
      "inherits": "npm:inherits@2.0.1",
      "process": "github:jspm/nodelibs-process@0.1.2"
    }
  }
});
<commit_msg>Changed a couple version numbers to match my original environment exactly<commit_after>System.config({
  defaultJSExtensions: true,
  transpiler: "babel",
  babelOptions: {
    "optional": [
      "es7.decorators",
      "es7.classProperties"
    ]
  },
  paths: {
    "*": "src/*",
    "github:*": "jspm_packages/github/*",
    "npm:*": "jspm_packages/npm/*"
  },

  map: {
    "aurelia-animator-css": "npm:aurelia-animator-css@1.0.0-beta.1.0.1",
    "aurelia-bootstrapper": "npm:aurelia-bootstrapper@1.0.0-beta.1",
    "aurelia-fetch-client": "npm:aurelia-fetch-client@1.0.0-beta.1",
    "aurelia-framework": "npm:aurelia-framework@1.0.0-beta.1.0.1",
    "aurelia-history-browser": "npm:aurelia-history-browser@1.0.0-beta.1",
    "aurelia-loader-default": "npm:aurelia-loader-default@1.0.0-beta.1.0.1",
    "aurelia-logging-console": "npm:aurelia-logging-console@1.0.0-beta.1",
    "aurelia-router": "npm:aurelia-router@1.0.0-beta.1",
    "aurelia-templating-binding": "npm:aurelia-templating-binding@1.0.0-beta.1",
    "aurelia-templating-resources": "npm:aurelia-templating-resources@1.0.0-beta.1.0.1",
    "aurelia-templating-router": "npm:aurelia-templating-router@1.0.0-beta.1.0.1",
    "babel": "npm:babel-core@5.8.34",
    "babel-runtime": "npm:babel-runtime@5.8.34",
    "bootstrap": "github:twbs/bootstrap@3.3.5",
    "core-js": "npm:core-js@1.2.6",
    "fetch": "github:github/fetch@0.10.1",
    "font-awesome": "npm:font-awesome@4.4.0",
    "text": "github:systemjs/plugin-text@0.0.3",
    "github:jspm/nodelibs-assert@0.1.0": {
      "assert": "npm:assert@1.3.0"
    },
    "github:jspm/nodelibs-path@0.1.0": {
      "path-browserify": "npm:path-browserify@0.0.0"
    },
    "github:jspm/nodelibs-process@0.1.2": {
      "process": "npm:process@0.11.2"
    },
    "github:jspm/nodelibs-util@0.1.0": {
      "util": "npm:util@0.10.3"
    },
    "github:twbs/bootstrap@3.3.5": {
      "jquery": "github:components/jquery@2.1.4"
    },
    "npm:assert@1.3.0": {
      "util": "npm:util@0.10.3"
    },
    "npm:aurelia-animator-css@1.0.0-beta.1.0.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1"
    },
    "npm:aurelia-binding@1.0.0-beta.1.0.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-bootstrapper@1.0.0-beta.1": {
      "aurelia-event-aggregator": "npm:aurelia-event-aggregator@1.0.0-beta.1",
      "aurelia-framework": "npm:aurelia-framework@1.0.0-beta.1.0.1",
      "aurelia-history": "npm:aurelia-history@1.0.0-beta.1",
      "aurelia-history-browser": "npm:aurelia-history-browser@1.0.0-beta.1",
      "aurelia-loader-default": "npm:aurelia-loader-default@1.0.0-beta.1.0.1",
      "aurelia-logging-console": "npm:aurelia-logging-console@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-pal-browser": "npm:aurelia-pal-browser@1.0.0-beta.1",
      "aurelia-router": "npm:aurelia-router@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1",
      "aurelia-templating-binding": "npm:aurelia-templating-binding@1.0.0-beta.1",
      "aurelia-templating-resources": "npm:aurelia-templating-resources@1.0.0-beta.1.0.1",
      "aurelia-templating-router": "npm:aurelia-templating-router@1.0.0-beta.1.0.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-dependency-injection@1.0.0-beta.1": {
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-event-aggregator@1.0.0-beta.1": {
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1"
    },
    "npm:aurelia-fetch-client@1.0.0-beta.1": {
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-framework@1.0.0-beta.1.0.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-history-browser@1.0.0-beta.1": {
      "aurelia-history": "npm:aurelia-history@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-http-client@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-loader-default@1.0.0-beta.1.0.1": {
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-loader@1.0.0-beta.1": {
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1"
    },
    "npm:aurelia-logging-console@1.0.0-beta.1": {
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-metadata@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-pal-browser@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-route-recognizer@1.0.0-beta.1": {
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-router@1.0.0-beta.1": {
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-event-aggregator": "npm:aurelia-event-aggregator@1.0.0-beta.1",
      "aurelia-history": "npm:aurelia-history@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-route-recognizer": "npm:aurelia-route-recognizer@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-task-queue@1.0.0-beta.1": {
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1"
    },
    "npm:aurelia-templating-binding@1.0.0-beta.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1"
    },
    "npm:aurelia-templating-resources@1.0.0-beta.1.0.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:aurelia-templating-router@1.0.0-beta.1.0.1": {
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-router": "npm:aurelia-router@1.0.0-beta.1",
      "aurelia-templating": "npm:aurelia-templating@1.0.0-beta.1"
    },
    "npm:aurelia-templating@1.0.0-beta.1": {
      "aurelia-binding": "npm:aurelia-binding@1.0.0-beta.1.0.1",
      "aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-beta.1",
      "aurelia-loader": "npm:aurelia-loader@1.0.0-beta.1",
      "aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1",
      "aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1",
      "aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1",
      "aurelia-path": "npm:aurelia-path@1.0.0-beta.1",
      "aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-beta.1",
      "core-js": "npm:core-js@1.2.6"
    },
    "npm:babel-runtime@5.8.34": {
      "process": "github:jspm/nodelibs-process@0.1.2"
    },
    "npm:core-js@1.2.6": {
      "fs": "github:jspm/nodelibs-fs@0.1.2",
      "path": "github:jspm/nodelibs-path@0.1.0",
      "process": "github:jspm/nodelibs-process@0.1.2",
      "systemjs-json": "github:systemjs/plugin-json@0.1.0"
    },
    "npm:font-awesome@4.4.0": {
      "css": "github:systemjs/plugin-css@0.1.19"
    },
    "npm:inherits@2.0.1": {
      "util": "github:jspm/nodelibs-util@0.1.0"
    },
    "npm:path-browserify@0.0.0": {
      "process": "github:jspm/nodelibs-process@0.1.2"
    },
    "npm:process@0.11.2": {
      "assert": "github:jspm/nodelibs-assert@0.1.0"
    },
    "npm:util@0.10.3": {
      "inherits": "npm:inherits@2.0.1",
      "process": "github:jspm/nodelibs-process@0.1.2"
    }
  }
});
<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var fs = require('fs');

var configKeys = ['githubUsername', 'authorName', 'authorEmail', 'authorUrl'];

var _defaultDependencies = [
  {name: 'lodash', description: 'A utility library delivering consistency, customization, performance, & extras'},
  {name: 'q', description: 'A library for promises'}
];

/**
 * The Generator settings
 * This is used to store the generators meta and dependencies information in a persistent data source.
 * @constructor
 */
var Config = module.exports = function Config(configPath) {
  this._meta = {};
  this._dependencies = [];
  this._configPath = configPath || path.join(__dirname, './settings.json');

  this._load();
};

/**
 * Loads the meta and dependencies data from the settings file
 */
Config.prototype._load = function _load() {
  if (fs.existsSync(this._configPath)) {
    var content = fs.readFileSync(this._configPath);
    content = JSON.parse(content);
    this._meta = content.meta;
    this._dependencies = content.dependencies;
  } else {
    this._dependencies = _defaultDependencies;
  }
};

/**
 * Store the meta and dependencies data in the settings file
 */
Config.prototype._write = function _write() {
  var content = {
    meta: this._meta,
    dependencies: this._dependencies,
  };
  content = JSON.stringify(content, '', 2);
  fs.writeFileSync(this._configPath, content);
};

/**
 * Get the stored generators dependencies
 * @return {Object} Generators dependencies
 */
Config.prototype.getDependencies = function getDependencies() {
  return this._dependencies;
};

/**
 * Get the stored generators meta data
 * @return {Object} Generators metadata
 */
Config.prototype.getMeta = function getMeta() {
  return this._meta;
};

/**
 * Store the given metadata in the settings file
 * @return {Object} Generators metadata
 */
Config.prototype.setMeta = function storeMeta(options) {
  configKeys.forEach(function (val) {
    if (options[val]) {
      this._meta[val] = options[val];
    }
  }.bind(this));
  this._write();
};
<commit_msg>Add debug as dependency<commit_after>'use strict';

var path = require('path');
var fs = require('fs');

var configKeys = ['githubUsername', 'authorName', 'authorEmail', 'authorUrl'];

var _defaultDependencies = [
  {name: 'lodash', description: 'A utility library'},
  {name: 'q', description: 'A library for promises'},
  {name: 'debug', description: 'tiny node.js debugging utility'}
];

/**
 * The Generator settings
 * This is used to store the generators meta and dependencies information in a persistent data source.
 * @constructor
 */
var Config = module.exports = function Config(configPath) {
  this._meta = {};
  this._dependencies = [];
  this._configPath = configPath || path.join(__dirname, './settings.json');

  this._load();
};

/**
 * Loads the meta and dependencies data from the settings file
 */
Config.prototype._load = function _load() {
  if (fs.existsSync(this._configPath)) {
    var content = fs.readFileSync(this._configPath);
    content = JSON.parse(content);
    this._meta = content.meta;
    this._dependencies = content.dependencies;
  } else {
    this._dependencies = _defaultDependencies;
  }
};

/**
 * Store the meta and dependencies data in the settings file
 */
Config.prototype._write = function _write() {
  var content = {
    meta: this._meta,
    dependencies: this._dependencies,
  };
  content = JSON.stringify(content, '', 2);
  fs.writeFileSync(this._configPath, content);
};

/**
 * Get the stored generators dependencies
 * @return {Object} Generators dependencies
 */
Config.prototype.getDependencies = function getDependencies() {
  return this._dependencies;
};

/**
 * Get the stored generators meta data
 * @return {Object} Generators metadata
 */
Config.prototype.getMeta = function getMeta() {
  return this._meta;
};

/**
 * Store the given metadata in the settings file
 * @return {Object} Generators metadata
 */
Config.prototype.setMeta = function storeMeta(options) {
  configKeys.forEach(function (val) {
    if (options[val]) {
      this._meta[val] = options[val];
    }
  }.bind(this));
  this._write();
};
<|endoftext|>


<commit_before>/**
 * uni://form-field
 */
import {
  hasOwn
} from 'uni-shared'

import {
  emitter
} from 'uni-mixins'

function created () {
  this.$dispatch('Form', 'uni-form-group-update', {
    type: 'add',
    vm: this
  })
}

function beforeDestroy () {
  this.$dispatch('Form', 'uni-form-group-update', {
    type: 'remove',
    vm: this
  })
}

export default {
  name: 'uni://form-field',
  init (options, vm) {
    if (
      !vm.constructor.options.props.name ||
            !vm.constructor.options.props.value
    ) { // 未初始化 props
      if (!vm.constructor.options.props.name) {
        vm.constructor.options.props.name = options.props.name = {
          type: String
        }
      }
      if (!vm.constructor.options.props.value) {
        vm.constructor.options.props.value = options.props.value = {
          type: null
        }
      }
    }

    if (!options.propsData) {
      options.propsData = {}
    }

    const $vnode = vm.$vnode
    if ($vnode && $vnode.data && $vnode.data.attrs) {
      if (hasOwn($vnode.data.attrs, 'name')) {
        options.propsData.name = $vnode.data.attrs.name
      }
      if (hasOwn($vnode.data.attrs, 'value')) {
        options.propsData.value = $vnode.data.attrs.value
      }
    }

    if (
      !vm.constructor.options.methods ||
            !vm.constructor.options.methods._getFormData
    ) { // 未初始化 methods
      if (!vm.constructor.options.methods) {
        vm.constructor.options.methods = {}
      }

      if (!options.methods) {
        options.methods = {}
      }

      const formMethods = {
        _getFormData () {
          return this.name ? {
            key: this.name,
            value: this.value
          } : {}
        },
        _resetFormData () {
          this.value = ''
        }
      }

      Object.assign(vm.constructor.options.methods, formMethods)
      Object.assign(options.methods, formMethods)

      // add $dispatch
      Object.assign(vm.constructor.options.methods, emitter.methods)
      Object.assign(options.methods, emitter.methods)

      const createdHooks = options['created']
      vm.constructor.options['created'] = options['created'] =
                createdHooks ? [].concat(created, createdHooks) : [
                  created
                ]

      const beforeDestroyHooks = options['beforeDestroy']
      vm.constructor.options['beforeDestroy'] = options['beforeDestroy'] =
                beforeDestroyHooks ? [].concat(beforeDestroy, beforeDestroyHooks) : [
                  beforeDestroy
                ]
    }
  }
}
<commit_msg>fix(h5): uni://form-field<commit_after>/**
 * uni://form-field
 */
import {
  hasOwn
} from 'uni-shared'

import {
  emitter
} from 'uni-mixins'

function created () {
  this.$dispatch('Form', 'uni-form-group-update', {
    type: 'add',
    vm: this
  })
}

function beforeDestroy () {
  this.$dispatch('Form', 'uni-form-group-update', {
    type: 'remove',
    vm: this
  })
}

export default {
  name: 'uni://form-field',
  init (options, vm) {
    if (
      !vm.constructor.options.props ||
            !vm.constructor.options.props.name ||
            !vm.constructor.options.props.value
    ) { // 未初始化 props
      if (!vm.constructor.options.props) {
        vm.constructor.options.props = {}
      }
      if (!vm.constructor.options.props.name) {
        vm.constructor.options.props.name = options.props.name = {
          type: String
        }
      }
      if (!vm.constructor.options.props.value) {
        vm.constructor.options.props.value = options.props.value = {
          type: null
        }
      }
    }

    if (!options.propsData) {
      options.propsData = {}
    }

    const $vnode = vm.$vnode
    if ($vnode && $vnode.data && $vnode.data.attrs) {
      if (hasOwn($vnode.data.attrs, 'name')) {
        options.propsData.name = $vnode.data.attrs.name
      }
      if (hasOwn($vnode.data.attrs, 'value')) {
        options.propsData.value = $vnode.data.attrs.value
      }
    }

    if (
      !vm.constructor.options.methods ||
            !vm.constructor.options.methods._getFormData
    ) { // 未初始化 methods
      if (!vm.constructor.options.methods) {
        vm.constructor.options.methods = {}
      }

      if (!options.methods) {
        options.methods = {}
      }

      const formMethods = {
        _getFormData () {
          return this.name ? {
            key: this.name,
            value: this.value
          } : {}
        },
        _resetFormData () {
          this.value = ''
        }
      }

      Object.assign(vm.constructor.options.methods, formMethods)
      Object.assign(options.methods, formMethods)

      // add $dispatch
      Object.assign(vm.constructor.options.methods, emitter.methods)
      Object.assign(options.methods, emitter.methods)

      const createdHooks = options['created']
      vm.constructor.options['created'] = options['created'] =
                createdHooks ? [].concat(created, createdHooks) : [
                  created
                ]

      const beforeDestroyHooks = options['beforeDestroy']
      vm.constructor.options['beforeDestroy'] = options['beforeDestroy'] =
                beforeDestroyHooks ? [].concat(beforeDestroy, beforeDestroyHooks) : [
                  beforeDestroy
                ]
    }
  }
}
<|endoftext|>


<commit_before>import { backtrack } from '../common/iterators';
import * as DS from '../dsymbols/delaney';

const _firstUndefined = data => {
  const i = data.indexOf(null);
  if (i >= 0)
    return [Math.floor(i / 3) + 1, i % 3];
};

const _size = data => data.length / 3;

const _get = (data, i, D) => data[(D - 1) * 3 + i];

const _set = (data, i, D, E) => {
  data[(D - 1) * 3 + i] = E;
  data[(E - 1) * 3 + i] = D;
};

const _makeDelaneySet = data => {
  const dim = 2;
  const size = _size(data);

  const s = new Array((dim + 1) * size).fill(0);

  for (let D = 1; D <= size; ++D) {
    for (let i = 0; i <= dim; ++i)
      s[i * size + D - 1] = _get(data, i, D);
  }

  return DS.makeDSymbol(dim, s, new Array(dim * size).fill(0));
};

const _scan = (data, w, D, limit) => {
  let [E, k] = [D, 0];

  while (k < limit && _get(data, w[k], E) != null)
    [E, k] = [_get(data, w[k], E), k + 1];

  return [E, k];
};

const _scan02Orbit = (data, D) => {
  const [head, i] = _scan(data, [0, 2, 0, 2], D, 4);
  const [tail, j] = _scan(data, [2, 0, 2, 0], D, 4 - i);
  const gap = 4 - i - j;
  return [head, tail, gap, 2 * (i % 2)];
};

const _potentialChildren = (data, maxSize) => {
  const size = _size(data);
  const limit = Math.min(size + 1, maxSize);
  const undef = _firstUndefined(data);

  const result = [];

  if (undef != null) {
    const [D, i] = undef;

    for (let E = D; E <= limit; ++E) {
      if (E > size)
        data = data.concat([null, null, null]);

      if (_get(data, i, E) == null) {
        const out = data.slice();
        _set(out, i, D, E);

        const [head, tail, gap, k] = _scan02Orbit(out, D);

        if (gap == 1) {
          _set(out, k, head, tail);
          result.push(out);
        }
        else if (gap > 0 || head == tail)
          result.push(out);
      }
    }
  }

  return result;
};

const _compareRenumberedFrom = (data, D0) => {
  const n2o = [ null, D0];
  const o2n = { [D0]: 1 };

  for (let D = 1; D <= _size(data); ++D) {
    if (D >= n2o.length)
      throw new Error("symbol is not transitive");

    for (const i of [0, 1, 2]) {
      const E = _get(data, i, n2o[D]);
      if (E != null && o2n[E] == null) {
        o2n[E] = n2o.length;
        n2o.push(E);
      }

      const nval = o2n[E];
      const oval = _get(data, i, D);
      if (oval != nval)
        return oval == null ? -1 : nval == null ? 1 : nval - oval;
    }
  }

  return 0;
};

const _isCanonical = data => {
  let result = true;

  for (let D = 1; D <= _size(data); ++D) {
    if (_compareRenumberedFrom(data, D) < 0) {
      result = false;
      break;
    }
  }

  return result;
};

export const delaneySets = maxSize => {
  const root = [null, null, null];

  const extract =
    data => _firstUndefined(data) ? null : _makeDelaneySet(data);

  const children =
    data => _potentialChildren(data, maxSize).filter(_isCanonical);

  return backtrack({ extract, root, children });
}
<commit_msg>branchings2d: eliminate underscores in function names<commit_after>import { backtrack } from '../common/iterators';
import * as DS from '../dsymbols/delaney';

const firstUndefined = data => {
  const i = data.indexOf(null);
  if (i >= 0)
    return [Math.floor(i / 3) + 1, i % 3];
};

const getSize = data => data.length / 3;

const get = (data, i, D) => data[(D - 1) * 3 + i];

const set = (data, i, D, E) => {
  data[(D - 1) * 3 + i] = E;
  data[(E - 1) * 3 + i] = D;
};

const makeDelaneySet = data => {
  const dim = 2;
  const size = getSize(data);

  const s = new Array((dim + 1) * size).fill(0);

  for (let D = 1; D <= size; ++D) {
    for (let i = 0; i <= dim; ++i)
      s[i * size + D - 1] = get(data, i, D);
  }

  return DS.makeDSymbol(dim, s, new Array(dim * size).fill(0));
};

const scan = (data, w, D, limit) => {
  let [E, k] = [D, 0];

  while (k < limit && get(data, w[k], E) != null)
    [E, k] = [get(data, w[k], E), k + 1];

  return [E, k];
};

const scan02Orbit = (data, D) => {
  const [head, i] = scan(data, [0, 2, 0, 2], D, 4);
  const [tail, j] = scan(data, [2, 0, 2, 0], D, 4 - i);
  const gap = 4 - i - j;
  return [head, tail, gap, 2 * (i % 2)];
};

const potentialChildren = (data, maxSize) => {
  const size = getSize(data);
  const limit = Math.min(size + 1, maxSize);
  const undef = firstUndefined(data);

  const result = [];

  if (undef != null) {
    const [D, i] = undef;

    for (let E = D; E <= limit; ++E) {
      if (E > size)
        data = data.concat([null, null, null]);

      if (get(data, i, E) == null) {
        const out = data.slice();
        set(out, i, D, E);

        const [head, tail, gap, k] = scan02Orbit(out, D);

        if (gap == 1) {
          set(out, k, head, tail);
          result.push(out);
        }
        else if (gap > 0 || head == tail)
          result.push(out);
      }
    }
  }

  return result;
};

const compareRenumberedFrom = (data, D0) => {
  const n2o = [ null, D0];
  const o2n = { [D0]: 1 };

  for (let D = 1; D <= getSize(data); ++D) {
    if (D >= n2o.length)
      throw new Error("symbol is not transitive");

    for (const i of [0, 1, 2]) {
      const E = get(data, i, n2o[D]);
      if (E != null && o2n[E] == null) {
        o2n[E] = n2o.length;
        n2o.push(E);
      }

      const nval = o2n[E];
      const oval = get(data, i, D);
      if (oval != nval)
        return oval == null ? -1 : nval == null ? 1 : nval - oval;
    }
  }

  return 0;
};

const isCanonical = data => {
  let result = true;

  for (let D = 1; D <= getSize(data); ++D) {
    if (compareRenumberedFrom(data, D) < 0) {
      result = false;
      break;
    }
  }

  return result;
};

export const delaneySets = maxSize => {
  const root = [null, null, null];

  const extract =
    data => firstUndefined(data) ? null : makeDelaneySet(data);

  const children =
    data => potentialChildren(data, maxSize).filter(isCanonical);

  return backtrack({ extract, root, children });
}
<|endoftext|>


<commit_before>function chooseFile(accept, multiple, extra) {
    var form = document.createElement("form");
    form.innerHTML = `<input ${extra ? extra + " " : ''}type='file'${accept ? ` accept="${accept}"` : ''}${multiple ? ' multiple' : ''} />`;
    var [input] = form.children;
    var result = new Promise(function (ok) {
        if (/msie\s+[2-9]/i.test(navigator.userAgent)) return alert("无法在当前浏览器操作！");
        on("change")(input, function () {
            if (!this.files) {
                var value = this.value;
                if (!value) return;
                var ActiveXObject = window.ActiveXObject;
                if (!ActiveXObject) {
                    alert("您的浏览器环境无法选择文件！");
                    return;
                }
                try {
                    var fso = new ActiveXObject('Scripting.FileSystemObject');
                    var file = fso.GetFile(value);
                    ok([file]);
                } catch (e) {
                    alert(e + "打开文件失败！");
                }
            } else {
                setTimeout(() => {
                    ok(this.files);
                }, 100);
            }
        });
    });
    input.click();
    return result;
}<commit_msg>防止文件窗口造成原生事件的中断<commit_after>function chooseFile(accept, multiple, extra) {
    var form = document.createElement("form");
    form.innerHTML = `<input ${extra ? extra + " " : ''}type='file'${accept ? ` accept="${accept}"` : ''}${multiple ? ' multiple' : ''} />`;
    var [input] = form.children;
    var result = new Promise(function (ok) {
        if (/msie\s+[2-9]/i.test(navigator.userAgent)) return alert("无法在当前浏览器操作！");
        on("change")(input, function () {
            if (!this.files) {
                var value = this.value;
                if (!value) return;
                var ActiveXObject = window.ActiveXObject;
                if (!ActiveXObject) {
                    alert("您的浏览器环境无法选择文件！");
                    return;
                }
                try {
                    var fso = new ActiveXObject('Scripting.FileSystemObject');
                    var file = fso.GetFile(value);
                    ok([file]);
                } catch (e) {
                    alert(e + "打开文件失败！");
                }
            } else {
                setTimeout(() => {
                    ok(this.files);
                }, 100);
            }
        });
    });
    setTimeout(function(){
        input.click();
    });
    return result;
}<|endoftext|>


<commit_before>// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2013-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
/**
 * @license
 * @fileoverview Flydown is an abstract class for a flyout-like dropdown containing blocks.
 *   Unlike a regular flyout, for simplicity it does not support scrolling.
 *   Any non-abstract subclass must provide a flydownBlocksXML_ () method that returns an
 *   XML element whose children are blocks that should appear in the flyout.
 * @author fturbak@wellesley.edu (Lyn Turbak)
 */
'use strict';

goog.provide('AI.Blockly.Flydown');

goog.require('Blockly.Flyout');
goog.require('Blockly.Block');
goog.require('Blockly.Comment');

/**
 * Class for a flydown.
 * @constructor
 */
Blockly.Flydown = function(workspaceOptions) {
  Blockly.Flydown.superClass_.constructor.call(this, workspaceOptions);
  this.dragAngleRange_ = 360;
};
goog.inherits(Blockly.Flydown, Blockly.Flyout);

/**
 * Previous CSS class for this flydown
 * @type {number}
 * @const
 */
Blockly.Flydown.prototype.previousCSSClassName_ = '';

/**
 * Override flyout factor to be smaller for flydowns
 * @type {number}
 * @const
 */
Blockly.Flydown.prototype.VERTICAL_SEPARATION_FACTOR = 1;

/**
 * Creates the flydown's DOM.  Only needs to be called once.  Overrides the flyout createDom method.
 * @param {!String} cssClassName The name of the CSS class for this flydown.
 * @return {!Element} The flydown's SVG group.
 */
Blockly.Flydown.prototype.createDom = function(cssClassName) {
  /*
  <g>
    <path class={cssClassName}/>
    <g></g>
  </g>
  */
  this.previousCSSClassName_ = cssClassName; // Remember class name for later
  this.svgGroup_ = Blockly.utils.createSvgElement('g', {'class': cssClassName}, null);
  this.svgBackground_ = Blockly.utils.createSvgElement('path', {}, this.svgGroup_);
  this.svgGroup_.appendChild(this.workspace_.createDom());
  return this.svgGroup_;
};

/**
 * Set the CSS class of the flydown SVG group. Need to remove previous class if there is one.
 * @param {!String} newCSSClassName The name of the new CSS class replacing the old one
 */
Blockly.Flydown.prototype.setCSSClass = function(newCSSClassName) {
  if (newCSSClassName !== this.previousCSSClassName_) {
    Blockly.utils.removeClass(this.svgGroup_, this.previousCSSClassName_);
    Blockly.utils.addClass(this.svgGroup_, newCSSClassName);
    this.previousCSSClassName_ = newCSSClassName;
  }
}

/**
 * Initializes the Flydown.
 * @param {!Blockly.Workspace} workspace The workspace in which to create new
 *     blocks.
 */
Blockly.Flydown.prototype.init = function(workspace) {
  Blockly.Flyout.prototype.init.call(this, workspace, false); // Flydowns have no scrollbar
}

/**
 * Override the flyout position method to do nothing instead
 * @private
 */
Blockly.Flydown.prototype.position = function() {
  return;
}

/**
 * Show and populate the flydown.
 * @param {!Array|string} xmlList List of blocks to show.
 * @param {!num} x x-position of upper-left corner of flydown
 * @param {!num} y y-position of upper-left corner of flydown
 */
Blockly.Flydown.prototype.showAt = function(xmlList,x,y) {
  Blockly.Events.disable();
  try {
    this.show(xmlList); // invoke flyout method, which adds blocks to flydown and calculates width and height.
  } finally {
    Blockly.Events.enable();
  }
  // this.svgGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')');
  // Calculate path around flydown blocks. Based on code in flyout position_ method.

  // Start at bottom of top left arc and proceed clockwise
  // Flydown outline shape is symmetric about vertical axis, so no need to differentiate LTR and RTL paths.
  var margin = this.CORNER_RADIUS * this.workspace_.scale;
  var edgeWidth = this.width_ - 2*margin;
  var edgeHeight = this.height_ - 2*margin;
  var path = ['M 0,' + margin];
  path.push('a', margin, margin, 0, 0, 1, margin, -margin); // upper left arc
  path.push('h', edgeWidth);  // top edge
  path.push('a', margin, margin, 0, 0, 1, margin, margin); // upper right arc
  path.push('v', edgeHeight); // right edge
  path.push('a', margin, margin, 0, 0, 1, -margin, margin); // bottom right arc
  path.push('h', -edgeWidth); // bottom edge, drawn backwards
  path.push('a', margin, margin, 0, 0, 1, -margin, -margin); // bottom left arc
  path.push('z'); // complete path by drawing left edge
  this.svgBackground_.setAttribute('d', path.join(' '));
  this.svgGroup_.setAttribute('transform', 'translate(' + x + ', ' + y + ')');
}

/**
 * Compute width and height of Flydown.  Position button under each block.
 * Overrides the reflow method of flyout
 * For RTL: Lay out the blocks right-aligned.
 */
Blockly.Flydown.prototype.reflow = function() {
  this.workspace_.scale = this.targetWorkspace_.scale;
  var scale = this.workspace_.scale;
  var flydownWidth = 0;
  var flydownHeight = 0;
  var margin = this.CORNER_RADIUS * scale;
  var blocks = this.workspace_.getTopBlocks(false);
  for (var i = 0, block; block = blocks[i]; i++) {
    var root = block.getSvgRoot();
    var blockHW = block.getHeightWidth();
    flydownWidth = Math.max(flydownWidth, blockHW.width * scale);
    flydownHeight += blockHW.height * scale;
  }
  flydownWidth += 2*margin + Blockly.BlockSvg.TAB_WIDTH * scale; // TAB_WIDTH is with of plug
  flydownHeight += 2*margin + margin*this.VERTICAL_SEPARATION_FACTOR*(blocks.length - 1) + Blockly.BlockSvg.START_HAT_HEIGHT*scale/2.0;
  if (this.width_ != flydownWidth) {
    for (var j = 0, block; block = blocks[j]; j++) {
      var blockHW = block.getHeightWidth();
      var blockXY = block.getRelativeToSurfaceXY();
      if (this.RTL) {
        // With the FlydownWidth known, right-align the blocks.
        var dx = flydownWidth - margin - scale * (Blockly.BlockSvg.TAB_WIDTH - blockXY.x);
        block.moveBy(dx, 0);
        blockXY.x += dx;
      }
      if (block.flyoutRect_) {
        block.flyoutRect_.setAttribute('width', blockHW.width);
        block.flyoutRect_.setAttribute('height', blockHW.height);
        block.flyoutRect_.setAttribute('x',
            this.RTL ? blockXY.x - blockHW.width : blockXY.x);
        block.flyoutRect_.setAttribute('y', blockXY.y);
      }
    }
    // Record the width for us in showAt method
    this.width_ = flydownWidth;
    this.height_ = flydownHeight;
  }
};

Blockly.Flydown.prototype.onMouseMove_ = function(e) {
  // override Blockly's flyout behavior for moving the flyout.
  return;
};

/**
 * Copy a block from the flyout to the workspace and position it correctly.
 * @param {!Blockly.Block} originBlock The flyout block to copy..
 * @return {!Blockly.Block} The new block in the main workspace.
 * @private
 */
Blockly.Flydown.prototype.placeNewBlock_ = function(originBlock) {
  var targetWorkspace = this.targetWorkspace_;
  var svgRootOld = originBlock.getSvgRoot();
  if (!svgRootOld) {
    throw 'originBlock is not rendered.';
  }
  // Figure out where the original block is on the screen, relative to the upper
  // left corner of the main workspace.
  var scale = this.workspace_.scale;
  var margin = this.CORNER_RADIUS * scale;
  var xyOld = this.workspace_.getSvgXY(svgRootOld);
  //var scrollX = this.svgGroup_.getScreenCTM().e + margin;
  var scrollX = xyOld.x;
  xyOld.x += scrollX / targetWorkspace.scale - scrollX;
  //var scrollY = this.svgGroup_.getScreenCTM().f + margin;
  var scrollY = xyOld.y;
  scale = targetWorkspace.scale;
  xyOld.y += scrollY / scale - scrollY;

  // Create the new block by cloning the block in the flyout (via XML).
  var xml = Blockly.Xml.blockToDom(originBlock);
  var block = Blockly.Xml.domToBlock(xml, targetWorkspace);
  var svgRootNew = block.getSvgRoot();
  if (!svgRootNew) {
    throw 'block is not rendered.';
  }
  // Figure out where the new block got placed on the screen, relative to the
  // upper left corner of the workspace.  This may not be the same as the
  // original block because the flyout's origin may not be the same as the
  // main workspace's origin.
  var xyNew = targetWorkspace.getSvgXY(svgRootNew);
  // Scale the scroll (getSvgXY did not do this).
  xyNew.x +=
      targetWorkspace.scrollX / targetWorkspace.scale - targetWorkspace.scrollX;
  xyNew.y +=
      targetWorkspace.scrollY / targetWorkspace.scale - targetWorkspace.scrollY;
  // If the flyout is collapsible and the workspace can't be scrolled.
  if (targetWorkspace.toolbox_ && !targetWorkspace.scrollbar) {
    xyNew.x += targetWorkspace.toolbox_.getWidth() / targetWorkspace.scale;
    xyNew.y += targetWorkspace.toolbox_.getHeight() / targetWorkspace.scale;
  }

  // Move the new block to where the old block is.
  block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y);
  return block;
};

Blockly.Flydown.prototype.shouldHide = true;

Blockly.Flydown.prototype.hide = function() {
  if (this.shouldHide) {
    Blockly.Flyout.prototype.hide.call(this);
    Blockly.FieldFlydown.openFieldFlydown_ = null;
  }
  this.shouldHide = true;
}

// Note: nothing additional beyond flyout disposal needs to be done to dispose of a flydown.
<commit_msg>Reposition flyouts depending on size and position so they appear on screen<commit_after>// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2013-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
/**
 * @license
 * @fileoverview Flydown is an abstract class for a flyout-like dropdown containing blocks.
 *   Unlike a regular flyout, for simplicity it does not support scrolling.
 *   Any non-abstract subclass must provide a flydownBlocksXML_ () method that returns an
 *   XML element whose children are blocks that should appear in the flyout.
 * @author fturbak@wellesley.edu (Lyn Turbak)
 */
'use strict';

goog.provide('AI.Blockly.Flydown');

goog.require('Blockly.Flyout');
goog.require('Blockly.Block');
goog.require('Blockly.Comment');

/**
 * Class for a flydown.
 * @constructor
 */
Blockly.Flydown = function(workspaceOptions) {
  Blockly.Flydown.superClass_.constructor.call(this, workspaceOptions);
  this.dragAngleRange_ = 360;
};
goog.inherits(Blockly.Flydown, Blockly.Flyout);

/**
 * Previous CSS class for this flydown
 * @type {number}
 * @const
 */
Blockly.Flydown.prototype.previousCSSClassName_ = '';

/**
 * Override flyout factor to be smaller for flydowns
 * @type {number}
 * @const
 */
Blockly.Flydown.prototype.VERTICAL_SEPARATION_FACTOR = 1;

/**
 * Creates the flydown's DOM.  Only needs to be called once.  Overrides the flyout createDom method.
 * @param {!String} cssClassName The name of the CSS class for this flydown.
 * @return {!Element} The flydown's SVG group.
 */
Blockly.Flydown.prototype.createDom = function(cssClassName) {
  /*
  <g>
    <path class={cssClassName}/>
    <g></g>
  </g>
  */
  this.previousCSSClassName_ = cssClassName; // Remember class name for later
  this.svgGroup_ = Blockly.utils.createSvgElement('g', {'class': cssClassName}, null);
  this.svgBackground_ = Blockly.utils.createSvgElement('path', {}, this.svgGroup_);
  this.svgGroup_.appendChild(this.workspace_.createDom());
  return this.svgGroup_;
};

/**
 * Set the CSS class of the flydown SVG group. Need to remove previous class if there is one.
 * @param {!String} newCSSClassName The name of the new CSS class replacing the old one
 */
Blockly.Flydown.prototype.setCSSClass = function(newCSSClassName) {
  if (newCSSClassName !== this.previousCSSClassName_) {
    Blockly.utils.removeClass(this.svgGroup_, this.previousCSSClassName_);
    Blockly.utils.addClass(this.svgGroup_, newCSSClassName);
    this.previousCSSClassName_ = newCSSClassName;
  }
}

/**
 * Initializes the Flydown.
 * @param {!Blockly.Workspace} workspace The workspace in which to create new
 *     blocks.
 */
Blockly.Flydown.prototype.init = function(workspace) {
  Blockly.Flyout.prototype.init.call(this, workspace, false); // Flydowns have no scrollbar
}

/**
 * Override the flyout position method to do nothing instead
 * @private
 */
Blockly.Flydown.prototype.position = function() {
  return;
}

/**
 * Show and populate the flydown.
 * @param {!Array|string} xmlList List of blocks to show.
 * @param {number} x x-position of upper-left corner of flydown
 * @param {number} y y-position of upper-left corner of flydown
 */
Blockly.Flydown.prototype.showAt = function(xmlList,x,y) {
  Blockly.Events.disable();
  try {
    this.show(xmlList); // invoke flyout method, which adds blocks to flydown and calculates width and height.
  } finally {
    Blockly.Events.enable();
  }
  // this.svgGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')');
  // Calculate path around flydown blocks. Based on code in flyout position_ method.

  // Start at bottom of top left arc and proceed clockwise
  // Flydown outline shape is symmetric about vertical axis, so no need to differentiate LTR and RTL paths.
  var targetWorkspaceMetrics = this.targetWorkspace_.getMetrics();
  var needsScrollbar = false;
  var contentBottom = targetWorkspaceMetrics.viewHeight + targetWorkspaceMetrics.absoluteTop;
  var flydownBottom = this.height_ + y;
  if (flydownBottom > contentBottom) {
    var overage = flydownBottom - contentBottom
    y = Math.max(y - overage, 0);  // don't go beyond the top of the workspace
    this.height_ = Math.min(this.height_ + overage, targetWorkspaceMetrics.viewHeight);  // don't go beyond the bottom of the workspace
    needsScrollbar = this.height_ >= targetWorkspaceMetrics.viewHeight;
  }
  var margin = this.CORNER_RADIUS * this.workspace_.scale;
  var edgeWidth = this.width_ - 2*margin;
  var edgeHeight = this.height_ - 2*margin;
  var path = ['M 0,' + margin];
  path.push('a', margin, margin, 0, 0, 1, margin, -margin); // upper left arc
  path.push('h', edgeWidth);  // top edge
  path.push('a', margin, margin, 0, 0, 1, margin, margin); // upper right arc
  path.push('v', edgeHeight); // right edge
  path.push('a', margin, margin, 0, 0, 1, -margin, margin); // bottom right arc
  path.push('h', -edgeWidth); // bottom edge, drawn backwards
  path.push('a', margin, margin, 0, 0, 1, -margin, -margin); // bottom left arc
  path.push('z'); // complete path by drawing left edge
  this.svgBackground_.setAttribute('d', path.join(' '));
  this.svgGroup_.setAttribute('transform', 'translate(' + x + ', ' + y + ')');
  if (this.scrollbar_) {
    this.scrollbar_.setOrigin(x, y);
    this.scrollbar_.set(0);
    this.scrollbar_.resize();
    if (!needsScrollbar) {
      this.scrollbar_.setVisible(false);  // resizing shows the scrollbar
    }
  }
}

/**
 * Compute width and height of Flydown.  Position button under each block.
 * Overrides the reflow method of flyout
 * For RTL: Lay out the blocks right-aligned.
 */
Blockly.Flydown.prototype.reflow = function() {
  this.workspace_.scale = this.targetWorkspace_.scale;
  var scale = this.workspace_.scale;
  var flydownWidth = 0;
  var flydownHeight = 0;
  var margin = this.CORNER_RADIUS * scale;
  var blocks = this.workspace_.getTopBlocks(false);
  for (var i = 0, block; block = blocks[i]; i++) {
    var root = block.getSvgRoot();
    var blockHW = block.getHeightWidth();
    flydownWidth = Math.max(flydownWidth, blockHW.width * scale);
    flydownHeight += blockHW.height * scale;
  }
  flydownWidth += 2*margin + Blockly.BlockSvg.TAB_WIDTH * scale; // TAB_WIDTH is with of plug
  flydownHeight += 2*margin + margin*this.VERTICAL_SEPARATION_FACTOR*(blocks.length - 1) + Blockly.BlockSvg.START_HAT_HEIGHT*scale/2.0;
  if (this.width_ != flydownWidth) {
    for (var j = 0, block; block = blocks[j]; j++) {
      var blockHW = block.getHeightWidth();
      var blockXY = block.getRelativeToSurfaceXY();
      if (this.RTL) {
        // With the FlydownWidth known, right-align the blocks.
        var dx = flydownWidth - margin - scale * (Blockly.BlockSvg.TAB_WIDTH - blockXY.x);
        block.moveBy(dx, 0);
        blockXY.x += dx;
      }
      if (block.flyoutRect_) {
        block.flyoutRect_.setAttribute('width', blockHW.width);
        block.flyoutRect_.setAttribute('height', blockHW.height);
        block.flyoutRect_.setAttribute('x',
            this.RTL ? blockXY.x - blockHW.width : blockXY.x);
        block.flyoutRect_.setAttribute('y', blockXY.y);
      }
    }
    // Record the width for us in showAt method
    this.width_ = flydownWidth;
    this.height_ = flydownHeight;
  }
};

Blockly.Flydown.prototype.onMouseMove_ = function(e) {
  // override Blockly's flyout behavior for moving the flyout.
  return;
};

/**
 * Copy a block from the flyout to the workspace and position it correctly.
 * @param {!Blockly.Block} originBlock The flyout block to copy..
 * @return {!Blockly.Block} The new block in the main workspace.
 * @private
 */
Blockly.Flydown.prototype.placeNewBlock_ = function(originBlock) {
  var targetWorkspace = this.targetWorkspace_;
  var svgRootOld = originBlock.getSvgRoot();
  if (!svgRootOld) {
    throw 'originBlock is not rendered.';
  }
  // Figure out where the original block is on the screen, relative to the upper
  // left corner of the main workspace.
  var scale = this.workspace_.scale;
  var margin = this.CORNER_RADIUS * scale;
  var xyOld = this.workspace_.getSvgXY(svgRootOld);
  //var scrollX = this.svgGroup_.getScreenCTM().e + margin;
  var scrollX = xyOld.x;
  xyOld.x += scrollX / targetWorkspace.scale - scrollX;
  //var scrollY = this.svgGroup_.getScreenCTM().f + margin;
  var scrollY = xyOld.y;
  scale = targetWorkspace.scale;
  xyOld.y += scrollY / scale - scrollY;

  // Create the new block by cloning the block in the flyout (via XML).
  var xml = Blockly.Xml.blockToDom(originBlock);
  var block = Blockly.Xml.domToBlock(xml, targetWorkspace);
  var svgRootNew = block.getSvgRoot();
  if (!svgRootNew) {
    throw 'block is not rendered.';
  }
  // Figure out where the new block got placed on the screen, relative to the
  // upper left corner of the workspace.  This may not be the same as the
  // original block because the flyout's origin may not be the same as the
  // main workspace's origin.
  var xyNew = targetWorkspace.getSvgXY(svgRootNew);
  // Scale the scroll (getSvgXY did not do this).
  xyNew.x +=
      targetWorkspace.scrollX / targetWorkspace.scale - targetWorkspace.scrollX;
  xyNew.y +=
      targetWorkspace.scrollY / targetWorkspace.scale - targetWorkspace.scrollY;
  // If the flyout is collapsible and the workspace can't be scrolled.
  if (targetWorkspace.toolbox_ && !targetWorkspace.scrollbar) {
    xyNew.x += targetWorkspace.toolbox_.getWidth() / targetWorkspace.scale;
    xyNew.y += targetWorkspace.toolbox_.getHeight() / targetWorkspace.scale;
  }

  // Move the new block to where the old block is.
  block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y);
  return block;
};

Blockly.Flydown.prototype.shouldHide = true;

Blockly.Flydown.prototype.hide = function() {
  if (this.shouldHide) {
    Blockly.Flyout.prototype.hide.call(this);
    Blockly.FieldFlydown.openFieldFlydown_ = null;
  }
  this.shouldHide = true;
}

// Note: nothing additional beyond flyout disposal needs to be done to dispose of a flydown.
<|endoftext|>