').append(clone).html();\r\n });\r\n\r\n // When the state changes, find the new SEO category information\r\n $scope.$watch(() => $stateParams.category, (newVal, oldVal) => {\r\n if (newVal !== oldVal) {\r\n this.updateCategoryInformation();\r\n }\r\n });\r\n\r\n $timeout(() => {\r\n this.updateCategoryInformation();\r\n });\r\n }\r\n updateCategoryInformation() {\r\n const { $location, $state, $stateParams, categoryFactory } = this;\r\n categoryFactory.getCategorySeo($stateParams.category).then((data) => {\r\n if (!data) {\r\n data = {};\r\n }\r\n\r\n this.currentCategorySeo = data;\r\n\r\n // When we've updated the category SEO, update the description and image, or fallback to the original if not set\r\n if (!this.currentCategorySeo || !this.currentCategorySeo.description || this.currentCategorySeo.description.length <= 0) {\r\n this.categoryDescription = this.originalDescriptionHtml;\r\n } else {\r\n this.categoryDescription = this.currentCategorySeo.description;\r\n }\r\n\r\n if (!this.currentCategorySeo || !this.currentCategorySeo.bannerImage || this.currentCategorySeo.bannerImage.length <= 0) {\r\n this.imageSrc = this.originalImageSrc;\r\n } else {\r\n this.imageSrc = this.currentCategorySeo.bannerImage;\r\n }\r\n\r\n if ($stateParams.category && $stateParams.category.length > 0) {\r\n if (!this.currentCategorySeo || !this.currentCategorySeo.title || this.currentCategorySeo.title.length <= 0) {\r\n this.title = $stateParams.category;\r\n } else {\r\n this.title = this.currentCategorySeo.title;\r\n }\r\n } else {\r\n this.title = this.originalTitle;\r\n }\r\n\r\n this.currentCategorySeo.canonicalLink = `${$location.protocol()}://${$location.host()}${$state.href($state.current.name)}`;\r\n });\r\n }\r\n}\r\n\r\nexport default /* @ngInject */ () => {\r\n const directive = {\r\n bindToController: true,\r\n controller: CategorySeoController,\r\n controllerAs: 'vm',\r\n link,\r\n replace: true,\r\n restrict: 'A',\r\n transclude: true,\r\n scope: {},\r\n template,\r\n };\r\n\r\n return directive;\r\n\r\n function link(scope) {\r\n let $keywords = $('meta[name=keywords]');\r\n let $description = $('meta[name=description]');\r\n let $canonical = $(\"link[rel='canonical']\");\r\n\r\n const hasOriginalSeoKeywords = $keywords.length > 0;\r\n const hasOriginalSeoDescription = $description.length > 0;\r\n const hasOriginalCanonicalLink = $(\"link[rel='canonical']\").length > 0;\r\n\r\n // Initialise original values, so we can return to them if we're not given any new ones\r\n const originalSeoTitle = $(document).attr('title');\r\n const originalSeoKeywords = $keywords.attr('content');\r\n const originalSeoDescription = $description.attr('content');\r\n const originalCanonicalLink = $canonical.attr('href');\r\n\r\n // The category has chanced, so update the meta tags\r\n scope.$watch('vm.currentCategorySeo', (newValue) => {\r\n // Refresh the variables - they might have changed\r\n $keywords = $('meta[name=keywords]');\r\n $description = $('meta[name=description]');\r\n $canonical = $(\"link[rel='canonical']\");\r\n\r\n const currentCategorySeo = newValue;\r\n\r\n let newSeoTitle = originalSeoTitle;\r\n let newSeoKeywords = originalSeoKeywords;\r\n let newSeoDescription = originalSeoDescription;\r\n let newCanonicalLink = originalCanonicalLink;\r\n\r\n if (currentCategorySeo) {\r\n if (currentCategorySeo.seoTitle && currentCategorySeo.seoTitle.length > 0) {\r\n newSeoTitle = currentCategorySeo.seoTitle;\r\n }\r\n\r\n if (currentCategorySeo.seoKeywords && currentCategorySeo.seoKeywords.length > 0) {\r\n newSeoKeywords = currentCategorySeo.seoKeywords;\r\n }\r\n\r\n if (currentCategorySeo.seoDescription && currentCategorySeo.seoDescription.length > 0) {\r\n newSeoDescription = currentCategorySeo.seoDescription;\r\n }\r\n\r\n if (currentCategorySeo.canonicalLink && currentCategorySeo.canonicalLink.length > 0) {\r\n newCanonicalLink = currentCategorySeo.canonicalLink;\r\n }\r\n }\r\n\r\n // Remove tags if they're not required (maybe didn't have one to begin with), or add them if they now are\r\n removeOrAddTag($keywords, hasOriginalSeoKeywords, originalSeoKeywords, newSeoKeywords, `
`);\r\n removeOrAddTag($description, hasOriginalSeoDescription, originalSeoDescription, newSeoDescription, `
`);\r\n removeOrAddTag($canonical, hasOriginalCanonicalLink, originalCanonicalLink, newCanonicalLink, `
`);\r\n\r\n // Update the tag's content\r\n $(document).attr('title', newSeoTitle);\r\n $keywords.attr('content', newSeoKeywords);\r\n $description.attr('content', newSeoDescription);\r\n $canonical.attr('href', newCanonicalLink);\r\n\r\n function removeOrAddTag($tag, hasOriginalTag, originalContent, newContent, defaultTag) {\r\n // If there wasn't one already, and we're assigning the default, remove it again\r\n if (!hasOriginalTag && originalContent === newContent) {\r\n $tag.remove(// If we have new meta content, but the tag doesn't exist, add it\r\n );\r\n } else if ($tag.length <= 0 && originalContent !== newContent) {\r\n $('head').append(defaultTag);\r\n }\r\n }\r\n }, true);\r\n }\r\n};\r\n","/* eslint-disable max-len */\r\nconst slideDuration = 300;\r\nconst delayInterval = 100; // 100 Ms = 0.1s\r\n\r\nexport default /* @ngInject */ () => {\r\n const self = {\r\n link,\r\n restrict: 'A',\r\n scope: {\r\n filterLoaded: '=',\r\n },\r\n };\r\n\r\n return self;\r\n\r\n function link(scope, element) {\r\n const $parent = $(element);\r\n const $groups = $parent.find('.group > a');\r\n\r\n checkLoaded();\r\n\r\n // Load filter by default\r\n scope.$watch('filterLoaded', (newValue, oldValue) => {\r\n if (newValue !== oldValue) {\r\n checkLoaded();\r\n }\r\n }, true);\r\n\r\n function checkLoaded() {\r\n if (scope.filterLoaded === true) {\r\n $groups.each((i, item) => {\r\n const $this = $(item);\r\n const $group = $this.closest('.group');\r\n const $toggle = $group.children('.drop');\r\n if ($group.hasClass('start-open')) {\r\n slideToggleGroup($toggle, null, true);\r\n }\r\n });\r\n }\r\n }\r\n\r\n $groups.click((e) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n const $this = $(e.currentTarget);\r\n\r\n const $notClicked = $('.groups .group .drop:visible').siblings('a').not($this);\r\n\r\n const $clickedGroup = $this.parent('.group');\r\n const $toggle = $clickedGroup.children('.drop');\r\n if ($notClicked.length > 0) {\r\n const $notClickedToggle = $notClicked.siblings('.drop');\r\n slideToggleGroup($notClickedToggle, () => {\r\n slideToggleGroup($toggle);\r\n });\r\n } else {\r\n slideToggleGroup($toggle);\r\n }\r\n });\r\n }\r\n};\r\n\r\nfunction slideToggleGroup($toggle, always, forceOpen) {\r\n const $group = $toggle.closest('.group');\r\n let startedOpened = false;\r\n if ($group.hasClass('open')) {\r\n startedOpened = true;\r\n }\r\n\r\n if (forceOpen === true) {\r\n startedOpened = false;\r\n }\r\n\r\n const toggleOptions = {\r\n duration: slideDuration,\r\n step: slideStep,\r\n always,\r\n done() {\r\n if (!startedOpened) {\r\n $group.addClass('open');\r\n }\r\n },\r\n };\r\n\r\n let delay = 0;\r\n if (startedOpened) {\r\n const childCount = $toggle.children().length;\r\n delay = delayInterval * childCount;\r\n if (delay > 0) {\r\n delay += 200;\r\n } // Add some time at the end, so the animations finish before the JS scrolls up\r\n $group.removeClass('open');\r\n }\r\n\r\n setTimeout(() => {\r\n $toggle.slideToggle(toggleOptions);\r\n }, delay);\r\n}\r\n\r\n/** Sets the margin to slide the main content down when the filter slides */\r\nfunction slideStep(now, tween) {\r\n if (tween.prop === 'height') {\r\n const $elem = $(tween.elem);\r\n $elem.closest('.groups').css('margin-bottom', `${now}px`);\r\n }\r\n}\r\n","/* eslint-disable max-len */\r\nexport default /* @ngInject */ () => {\r\n const directive = {\r\n replace: true,\r\n controllerAs: 'vm',\r\n bindToController: true,\r\n restrict: 'A',\r\n link(scope, element, attrs) {\r\n function setGridWidth() {\r\n let colWidth = attrs.gridColWidth;\r\n\r\n if (!colWidth) {\r\n colWidth = 320;\r\n }\r\n\r\n const windowWidth = window.innerWidth;\r\n const colAmount = windowWidth / colWidth;\r\n let girdWidth;\r\n\r\n if (colAmount < 1) {\r\n girdWidth = Math.floor(1) * colWidth;\r\n } else {\r\n girdWidth = Math.floor(colAmount) * colWidth;\r\n }\r\n\r\n element.css({\r\n width: girdWidth,\r\n });\r\n }\r\n setGridWidth();\r\n $(window).resize(() => {\r\n setGridWidth();\r\n });\r\n },\r\n };\r\n\r\n return directive;\r\n};\r\n","/* eslint-disable max-len */\r\nimport sortBy from 'lodash/sortBy';\r\nimport uniq from 'lodash/uniq';\r\n\r\n/**\r\n * TODO: Make the main site product list use a version of this.\r\n * The different at the moment is this uses a load more button whilst the main list auto loads.\r\n */\r\n\r\nexport default /* @ngInject */ () => {\r\n const directive = {\r\n replace: true,\r\n controller: ProductListController,\r\n controllerAs: 'vm',\r\n bindToController: true,\r\n restrict: 'A',\r\n scope: {},\r\n templateUrl: '/sitefiles/src/ui/js/templates/ProductList.aspx',\r\n };\r\n\r\n return directive;\r\n};\r\n\r\n/* @ngInject */\r\nfunction ProductListController($attrs, $element, $filter, $scope, $window, productListFactory) {\r\n const vm = this;\r\n vm.pagedItemsResult = [];\r\n vm.pagedItems = pagedItems;\r\n vm.getClearfixClasses = getClearfixClasses;\r\n vm.pagination = {\r\n pageid: 1,\r\n itemsPerPage: 10,\r\n pagesize: getPageSize,\r\n };\r\n vm.loadMore = loadMore;\r\n vm.viewAll = viewAll;\r\n vm.showLoadMore = showLoadMore;\r\n vm.loaded = false;\r\n vm.categoryList = [];\r\n vm.selectedCategory = '';\r\n vm.hideReviews = $attrs.hideReviews === undefined ? false : $attrs.hideReviews === 'true';\r\n vm.hideCompare = $attrs.hideCompare === undefined ? false : $attrs.hideCompare === 'true';\r\n vm.hideApplicationShot = $attrs.hideApplicationShot === undefined ? false : $attrs.hideApplicationShot === 'true';\r\n vm.showProductCount = $attrs.showProductCount === undefined ? false : $attrs.showProductCount === 'true';\r\n vm.showingCount = getShowingCount;\r\n vm.totalCount = getProductCount;\r\n const agilityIds = $attrs.agilityIds.split(';');\r\n\r\n const filters = {\r\n agilityIds,\r\n ignoreUrl: true,\r\n };\r\n\r\n let allProducts = [];\r\n\r\n productListFactory.getProducts(filters).then((data) => {\r\n allProducts = data;\r\n vm.loaded = true;\r\n\r\n angular.forEach(allProducts, (value) => {\r\n Array.prototype.push.apply(vm.categoryList, value.Category);\r\n });\r\n\r\n vm.categoryList = sortBy(vm.categoryList, x => x);\r\n\r\n vm.categoryList = uniq(vm.categoryList, true);\r\n });\r\n\r\n function getShowingCount() {\r\n const products = $filter('ProductTabsCategory')(allProducts, vm.selectedCategory);\r\n const limitedProducts = $filter('limitTo')(products, vm.pagination.pagesize(), 0);\r\n return limitedProducts.length;\r\n }\r\n\r\n function getProductCount() {\r\n const products = $filter('ProductTabsCategory')(allProducts, vm.selectedCategory);\r\n return products.length;\r\n }\r\n\r\n /**\r\n * Returns the current page size\r\n */\r\n function getPageSize() {\r\n // If prerender exists in the user agent, then this is probably a request from google,\r\n // so show all products available rather than listing because it won't see the second page\r\n if (allProducts && $window.navigator.userAgent.match(/prerender/i)) {\r\n return allProducts.length;\r\n }\r\n\r\n return vm.pagination.itemsPerPage * vm.pagination.pageid;\r\n }\r\n\r\n function showLoadMore() {\r\n const products = $filter('ProductTabsCategory')(allProducts, vm.selectedCategory);\r\n if (products && vm.pagination.pagesize() < products.length) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Returns the products to be displayed on the current page\r\n */\r\n function pagedItems() {\r\n const products = $filter('ProductTabsCategory')(allProducts, vm.selectedCategory);\r\n return $filter('limitTo')(products, vm.pagination.pagesize(), 0);\r\n }\r\n\r\n function loadMore() {\r\n vm.pagination.pageid += 1;\r\n }\r\n\r\n function viewAll() {\r\n vm.pagination.pageid = vm.pagination.pagesize();\r\n }\r\n\r\n /**\r\n * Gets classes to conditionally display between each product list item\r\n */\r\n function getClearfixClasses(index) {\r\n const classArray = [];\r\n\r\n if ((index + 1) % 5 === 0) {\r\n classArray.push('visible-lg clearfix');\r\n }\r\n\r\n if ((index + 1) % 4 === 0) {\r\n classArray.push('visible-md clearfix');\r\n }\r\n\r\n if ((index + 1) % 2 === 0) {\r\n classArray.push('visible-sm clearfix');\r\n }\r\n\r\n if ((index + 1) % 1 === 0) {\r\n classArray.push('visible-xs clearfix');\r\n }\r\n\r\n return classArray;\r\n }\r\n}\r\n","/* eslint-disable max-len */\r\nimport get from 'lodash/get';\r\nimport includes from 'lodash/includes';\r\n\r\nexport default /* @ngInject */ () => {\r\n const directive = {\r\n replace: true,\r\n controller: ProductItemController,\r\n restrict: 'E',\r\n scope: {\r\n product: '=?',\r\n agilityId: '=?',\r\n hideCompare: '=?',\r\n hideReviews: '=?',\r\n hideApplicationShot: '=?',\r\n },\r\n templateUrl: '/sitefiles/src/ui/js/templates/ProductItem.aspx',\r\n };\r\n\r\n return directive;\r\n};\r\n\r\n/* @ngInject */\r\nfunction ProductItemController(\r\n $attrs,\r\n $element,\r\n $scope,\r\n productListFactory,\r\n productComparisonFactory,\r\n) {\r\n // If we haven't passed in a product object, use the agilityId if we've provided it instead\r\n if (!$scope.product) {\r\n $scope.product = null;\r\n\r\n const agilityId = parseInt($scope.agilityId, 10);\r\n if (agilityId > 0) {\r\n productListFactory.getProducts({ agilityIds: [agilityId] }).then(data => {\r\n if (data && data.length > 0) {\r\n $scope.product = data[0];\r\n }\r\n });\r\n }\r\n }\r\n\r\n $scope.formatImageUrl = (baseImageUrl, resizeWidth) => {\r\n if (baseImageUrl === undefined || baseImageUrl === null) {\r\n return baseImageUrl;\r\n }\r\n\r\n if (resizeWidth) {\r\n if (baseImageUrl.indexOf('?') > -1) {\r\n return `${baseImageUrl}&width=${resizeWidth}`;\r\n }\r\n\r\n return `${baseImageUrl}?width=${resizeWidth}`;\r\n }\r\n\r\n return baseImageUrl;\r\n };\r\n\r\n /**\r\n * Returns an array of a given size\r\n */\r\n $scope.getArray = items => new Array(items);\r\n\r\n /**\r\n * Refreshes the basic compare settings from the server\r\n */\r\n const refreshCompareSettings = () => {\r\n productComparisonFactory.getCompareSettings();\r\n };\r\n\r\n /**\r\n * Fired when the a compare checkbox is altered - the comparison is set/unset on the server,\r\n * the client is updated accordingly, and then the server updates for completeness\r\n */\r\n $scope.compareChange = (e, product) => {\r\n if (e) e.preventDefault();\r\n\r\n // Log a compare\r\n const $lng = $('#lng');\r\n if ($lng.length > 0) {\r\n productComparisonFactory.logCompare($lng.val());\r\n }\r\n\r\n if (!productComparisonFactory.compareSettings.ComparedProducts) {\r\n productComparisonFactory.compareSettings.ComparedProducts = [];\r\n }\r\n\r\n // Make an ajax call to unset it on the server for the user\r\n productComparisonFactory.compareChange(product.AgilityID).then(() => {\r\n const comparedAgilityIds = get(\r\n productComparisonFactory.compareSettings.ComparedProducts,\r\n 'AgilityID',\r\n );\r\n\r\n // Add/remove items from the array in the client (for speed) before we make an ajax call to the server to confirm the changes\r\n if (!product.IsCompared && includes(comparedAgilityIds, product.AgilityID)) {\r\n // If we're removing from the compare list, check if the item is in the list and remove it\r\n const index = comparedAgilityIds.indexOf(product.AgilityID);\r\n if (index > -1) {\r\n productComparisonFactory.compareSettings.ComparedProducts.splice(index, 1);\r\n }\r\n } else if (product.IsCompared && !includes(comparedAgilityIds, product.AgilityID)) {\r\n // If we're adding to the compare list, add the item\r\n productComparisonFactory.compareSettings.ComparedProducts.push(product);\r\n }\r\n\r\n // Then reset our local variables\r\n refreshCompareSettings();\r\n });\r\n };\r\n\r\n /**\r\n * Defines if the compare checkbox is visible or not\r\n */\r\n $scope.showCompareBox = product => {\r\n if (!productComparisonFactory.compareSettings) {\r\n return true;\r\n }\r\n\r\n if (!productComparisonFactory.compareSettings.ComparedProducts) {\r\n return true;\r\n }\r\n\r\n if (\r\n productComparisonFactory.compareSettings.ComparedProducts.length <\r\n productComparisonFactory.compareSettings.MaximumComparable\r\n ) {\r\n return true;\r\n }\r\n\r\n const comparedAgilityIds = get(\r\n productComparisonFactory.compareSettings.ComparedProducts,\r\n 'AgilityID',\r\n );\r\n if (includes(comparedAgilityIds, product.AgilityID)) {\r\n return true;\r\n }\r\n\r\n return false;\r\n };\r\n\r\n // Number of stars to show for each review\r\n $scope.numberOfStars = 5;\r\n\r\n /**\r\n * Gets the number of review stars to be populated for the chosen product\r\n */\r\n $scope.filledStars = product => {\r\n if (!product || product.DocumentRatingValue === 0 || product.DocumentRatings === 0) {\r\n return 0;\r\n }\r\n\r\n return Math.round(\r\n (product.DocumentRatingValue / product.DocumentRatings) * $scope.numberOfStars,\r\n );\r\n };\r\n\r\n $scope.$watch(\r\n () => getCompareSettingsWatch(),\r\n (newValue, oldValue) => {\r\n if (newValue !== oldValue) {\r\n const newComparedIds = get(newValue, 'AgilityID');\r\n\r\n productListFactory.products = productListFactory.products.forEach(p => {\r\n if (includes(newComparedIds, p.AgilityID)) {\r\n p.IsCompared = true;\r\n } else {\r\n p.IsCompared = false;\r\n }\r\n });\r\n }\r\n },\r\n );\r\n\r\n function getCompareSettingsWatch() {\r\n return productComparisonFactory.compareSettings\r\n ? productComparisonFactory.compareSettings.ComparedProducts\r\n : null;\r\n }\r\n}\r\n","/* eslint-disable max-len */\r\nexport default /* @ngInject */ (appSettings) => {\r\n const self = {\r\n link,\r\n restrict: 'A',\r\n scope: {\r\n controller: '=netcScrollMagic',\r\n options: '=?netcScrollMagicOptions',\r\n scene: '=?netcScrollMagicScene',\r\n\r\n // Events\r\n enter: '=?netcScrollMagicOnenter',\r\n end: '=?netcScrollMagicOnend',\r\n leave: '=?netcScrollMagicOnleave',\r\n start: '=?netcScrollMagicOnstart',\r\n },\r\n };\r\n\r\n return self;\r\n\r\n function link(scope, element) {\r\n require.ensure(['scrollmagic-core', 'scrollmagic-gsap'], () => {\r\n const ScrollMagic = require('scrollmagic-core');\r\n require('scrollmagic-gsap');\r\n\r\n // Ensure controller exists.\r\n if (scope.controller == null) {\r\n scope.controller = new ScrollMagic.Controller();\r\n }\r\n\r\n // Create scene and add to controller.\r\n const localOptions = scope.options;\r\n localOptions.triggerElement = element[0];\r\n scope.scene = new ScrollMagic.Scene(localOptions).addTo(scope.controller);\r\n\r\n // Add event handlers.\r\n if (scope.enter) scope.scene.on('enter', scope.enter);\r\n if (scope.end) scope.scene.on('end', scope.end);\r\n if (scope.leave) scope.scene.on('leave', scope.leave);\r\n if (scope.start) scope.scene.on('start', scope.start);\r\n\r\n // Add indicators in debug mode.\r\n if (appSettings.debugMode && scope.scene.addIndicators) scope.scene.addIndicators();\r\n });\r\n }\r\n};\r\n","import categorySeo from './categorySeo';\r\nimport fancyBox from './fancyBox';\r\nimport filterExpand from './filterExpand';\r\nimport gridSize from './gridSize';\r\nimport isotopeGrid from './isotopeGrid';\r\nimport productList from './productList';\r\nimport productItem from './productItem';\r\nimport scrollBar from './scrollBar';\r\nimport scrollMagic from './scrollMagic';\r\n\r\n\r\nconst module = angular.module('ryobi.directives', [])\r\n .directive('categorySeo', categorySeo)\r\n .directive('netcFancyBox', fancyBox)\r\n .directive('netcFilterExpand', filterExpand)\r\n .directive('gridSize', gridSize)\r\n .directive('isotopeGrid', isotopeGrid)\r\n .directive('productItem', productItem)\r\n .directive('productList', productList)\r\n .directive('scrollBar', scrollBar)\r\n .directive('netcScrollMagic', scrollMagic);\r\n\r\nexport default module;\r\n","/* eslint-disable max-len */\r\nimport fancybox from 'modules/fancybox'; // eslint-disable-line\r\n\r\nexport default /* @ngInject */ () => {\r\n const self = {\r\n link,\r\n restrict: 'A',\r\n scope: {\r\n applyFancybox: '=',\r\n },\r\n };\r\n\r\n function link(scope, element, attributes) {\r\n const href = attributes.ngHref || attributes.href;\r\n\r\n if (href && href.indexOf('youtube') > -1) {\r\n fancybox.applyFancyBoxVideo(element);\r\n\r\n // Check if the video needs to be auto-played once the template has rendered.\r\n setTimeout(() => {\r\n fancybox.autoPlayVideo(element);\r\n }, 0);\r\n }\r\n }\r\n\r\n return self;\r\n};\r\n","/* eslint-disable max-len */\r\nimport 'isotope-layout';\r\nimport 'isotope-packery';\r\n\r\n// Taken from https://github.com/diego-vieira/ng-isotope\r\n// The original didn't appear to $inject $timeout\r\n\r\nexport default /* @ngInject */ ($timeout) => {\r\n const directive = {\r\n replace: true,\r\n controllerAs: 'vm',\r\n restrict: 'A',\r\n scope: {\r\n items: '=isotopeGrid',\r\n },\r\n link(scope, element, attrs) {\r\n const options = {\r\n itemSelector: '.iso-grid--item',\r\n layoutMode: 'packery',\r\n masonry: {\r\n columnWidth: 320,\r\n fitWidth: true,\r\n },\r\n };\r\n\r\n element.isotope(options);\r\n\r\n scope.$watch('items', () => {\r\n $timeout(() => {\r\n element.isotope('reloadItems').isotope(options);\r\n });\r\n }, true);\r\n\r\n\r\n if (typeof attrs.isotopeReloadEvent !== 'undefined') {\r\n scope.$on(attrs.isotopeReloadEvent, () => {\r\n $timeout(() => {\r\n element.isotope('reloadItems').isotope(options);\r\n });\r\n });\r\n }\r\n },\r\n };\r\n\r\n return directive;\r\n};\r\n","/* eslint-disable max-len */\r\nimport 'jquery-mousewheel';\r\nimport 'malihu-custom-scrollbar-plugin';\r\n\r\nexport default /* @ngInject */ () => {\r\n const self = {\r\n restrict: 'A',\r\n link,\r\n scope: {},\r\n };\r\n\r\n function link(scope, element) {\r\n element.mCustomScrollbar({ alwaysShowScrollbar: 1 });\r\n }\r\n\r\n return self;\r\n};\r\n","import categoryFilter from './categoryFilter';\r\nimport productTabsCategoryFilter from './productTabsCategoryFilter';\r\n\r\nconst module = angular.module('ryobi.filters', [])\r\n .filter('Category', categoryFilter)\r\n .filter('ProductTabsCategory', productTabsCategoryFilter);\r\n\r\nexport default module;\r\n","import every from 'lodash/every';\r\nimport filter from 'lodash/filter';\r\nimport get from 'lodash/get';\r\nimport includes from 'lodash/includes';\r\n\r\nexport default /* @ngInject */ () => (items, categories) => {\r\n // If we've selected a category filter, then filter the list\r\n if (categories) {\r\n // Get the category names from the chosen categories\r\n let selectedCategoryNames = get(categories, 'CategoryDisplayName');\r\n\r\n // Filter out any null values\r\n selectedCategoryNames = filter(selectedCategoryNames, x => x);\r\n\r\n if (selectedCategoryNames.length > 0) {\r\n // Filter the items\r\n items = items.filter((n) => {\r\n const currentCategoryNames = n.Categories;\r\n\r\n // Returns true if all of the filters match an item\r\n return every(selectedCategoryNames, (catName) => {\r\n if (catName) {\r\n return includes(currentCategoryNames, catName);\r\n }\r\n\r\n return false;\r\n });\r\n });\r\n }\r\n }\r\n\r\n return items;\r\n};\r\n","import includes from 'lodash/includes';\r\n\r\nexport default /* @ngInject */ () => (items, selectedCategory) => {\r\n const filteredItems = [];\r\n\r\n // If we've selected a category filter, then filter the list\r\n if (selectedCategory) {\r\n angular.forEach(items, (value) => {\r\n if (includes(value.Category, selectedCategory)) {\r\n filteredItems.push(value);\r\n }\r\n });\r\n } else {\r\n return items;\r\n }\r\n\r\n return filteredItems;\r\n};\r\n","/** Kentico ngTranslate localisation factory. */\r\nconst KenticoLocalisationFactory = /* @ngInject */ $http => (options) => {\r\n const cultureCode = options.key;\r\n const key = `localisations-${cultureCode}`;\r\n\r\n return getStorage(key).then(\r\n localisations => localisations,\r\n () => {\r\n const params = {\r\n defaultCulture: 'en-US',\r\n };\r\n\r\n return $http.get(`/api/localisation/${cultureCode}`, { params }).then(\r\n (res) => {\r\n const localisations = res.data;\r\n return setStorage(key, localisations).then(\r\n () => localisations,\r\n () => localisations,\r\n );\r\n },\r\n () => Promise.reject(),\r\n );\r\n },\r\n );\r\n};\r\n\r\n/** Get value from storage. */\r\nfunction getStorage(key) {\r\n try {\r\n if (typeof Storage === 'undefined') {\r\n return Promise.reject();\r\n }\r\n\r\n if (!sessionStorage[key]) {\r\n return Promise.reject();\r\n }\r\n\r\n const json = sessionStorage[key];\r\n const localisations = JSON.parse(json);\r\n return Promise.resolve(localisations);\r\n } catch (e) {\r\n return Promise.reject();\r\n }\r\n}\r\n\r\n/** Set value in storage. */\r\nfunction setStorage(key, value) {\r\n try {\r\n if (typeof Storage === 'undefined') {\r\n return Promise.reject();\r\n }\r\n\r\n sessionStorage[key] = JSON.stringify(value);\r\n return Promise.resolve(value);\r\n } catch (e) {\r\n return Promise.reject();\r\n }\r\n}\r\n\r\nexport default KenticoLocalisationFactory;\r\n","import localisationFactory from './localisation.factory';\r\n\r\nexport default angular.module('ryobi.localisation', ['pascalprecht.translate'])\r\n .factory('localisationFactory', localisationFactory)\r\n .config(configureModule);\r\n\r\n/* @ngInject */\r\nfunction configureModule($translateProvider) {\r\n const defaultCulture = document.getElementById('lng').value;\r\n $translateProvider.preferredLanguage(defaultCulture);\r\n $translateProvider.useSanitizeValueStrategy('sanitizeParameters');\r\n $translateProvider.useLoaderCache(true);\r\n $translateProvider.useLoader('localisationFactory');\r\n}\r\n","export default /* @ngInject */ ($locationProvider, $stateProvider, $urlRouterProvider) => {\r\n const $blogPostList = $('.blog-list');\r\n\r\n if (!$blogPostList.length) {\r\n return;\r\n }\r\n\r\n $stateProvider.state('blog', {\r\n controller: 'BlogController',\r\n templateUrl: 'blog-list.html',\r\n url: '/{pageid:int}?{category:string}&{search:string}',\r\n });\r\n\r\n $urlRouterProvider.otherwise('/1');\r\n};\r\n","export default /* @ngInject */ ($locationProvider, $stateProvider, $urlRouterProvider) => {\r\n const $faqList = $('.faq-list');\r\n\r\n if (!$faqList.length) {\r\n return;\r\n }\r\n\r\n $stateProvider.state('faqList', {\r\n views: {\r\n 'faq-list': {\r\n templateUrl: 'faq-list.html',\r\n controller: 'FaqsController',\r\n },\r\n 'faq-filter': {\r\n templateUrl: 'faq-filter.html',\r\n controller: 'FaqsController',\r\n },\r\n },\r\n url: '/{category:string}?{search:string}',\r\n });\r\n\r\n $urlRouterProvider.otherwise('/');\r\n};\r\n","export default /* @ngInject */ ($locationProvider, $stateProvider, $urlRouterProvider) => {\r\n const $insightsList = $('.insights-list');\r\n\r\n if (!$insightsList.length) {\r\n return;\r\n }\r\n\r\n $stateProvider.state('insightsList', {\r\n views: {\r\n 'insights-list': {\r\n templateUrl: 'insights-list.html',\r\n controller: 'InsightsController',\r\n },\r\n 'insights-filter': {\r\n templateUrl: 'insights-filter.html',\r\n controller: 'InsightsController',\r\n },\r\n },\r\n url: '/{pageid:int}?{category:string}?{videos:bool}',\r\n });\r\n\r\n $urlRouterProvider.otherwise('/1');\r\n};\r\n","export default /* @ngInject */ ($locationProvider, $stateProvider, $urlRouterProvider) => {\r\n const $cordlessList = $('.cordless__product-display--content');\r\n const $productList = $('.js-product-list');\r\n const $productCodeFilter = $('.product-code-filter');\r\n\r\n if ($cordlessList.length) {\r\n return;\r\n }\r\n\r\n if (!$productList.length) {\r\n return;\r\n }\r\n\r\n if ($productCodeFilter.length) {\r\n $stateProvider.state('productList', {\r\n resolve: {\r\n productFilters: /* @ngInject */ productListFactory => productListFactory.getFilters(),\r\n routeProxy: /* @ngInject */ productListFactory => productListFactory.getRouteProxy(),\r\n },\r\n views: {\r\n 'product-list': {\r\n templateUrl: 'product-list.html',\r\n controller: 'ProductListController',\r\n },\r\n 'product-filter': {\r\n templateUrl: 'product-filter.html',\r\n controller: 'ProductListController',\r\n },\r\n 'product-code-filter': {\r\n templateUrl: 'product-code-filter.html',\r\n controller: 'ProductListController',\r\n },\r\n },\r\n // eslint-disable-next-line max-len\r\n url: '/{pageid:int}?{category:string}&{powersource:string}&{status:string}&{batteries:string}&{productcode:string}',\r\n });\r\n } else {\r\n $stateProvider.state('productList', {\r\n resolve: {\r\n productFilters: /* @ngInject */ productListFactory => productListFactory.getFilters(),\r\n routeProxy: /* @ngInject */ productListFactory => productListFactory.getRouteProxy(),\r\n },\r\n views: {\r\n 'product-list': {\r\n templateUrl: 'product-list.html',\r\n controller: 'ProductListController',\r\n },\r\n 'product-filter': {\r\n templateUrl: 'product-filter.html',\r\n controller: 'ProductListController',\r\n },\r\n },\r\n // eslint-disable-next-line max-len\r\n url: '/{pageid:int}?{category:string}&{powersource:string}&{status:string}&{batteries:string}&{productcode:string}&{groupedAll:string}&{unknown1:string}&{unknown2:string}&{unknown3:string}',\r\n });\r\n }\r\n\r\n $urlRouterProvider.otherwise('/1');\r\n};\r\n","export default /* @ngInject */ ($locationProvider, $stateProvider, $urlRouterProvider) => {\r\n const $supportArticlesList = $('.support-articles-list');\r\n\r\n if (!$supportArticlesList.length) {\r\n return;\r\n }\r\n\r\n $stateProvider.state('supportArticlesList', {\r\n views: {\r\n 'support-articles-list': {\r\n templateUrl: 'support-articles-list.html',\r\n controller: 'SupportController',\r\n },\r\n 'support-categories': {\r\n templateUrl: 'support-categories.html',\r\n controller: 'SupportController',\r\n },\r\n },\r\n url: '/{category:string}',\r\n });\r\n\r\n $urlRouterProvider.otherwise('/');\r\n};\r\n","export default /* @ngInject */ ($locationProvider, $stateProvider, $urlRouterProvider) => {\r\n const $videoList = $('.video-list');\r\n const $videoFilters = $('.video-filters');\r\n\r\n if (!$videoList.length) {\r\n return;\r\n }\r\n\r\n if ($videoFilters.length) {\r\n $stateProvider.state('videoList', {\r\n views: {\r\n 'video-list': {\r\n templateUrl: 'video-list.html',\r\n controller: 'VideoListController',\r\n },\r\n 'video-filter': {\r\n templateUrl: 'video-filter.html',\r\n controller: 'VideoListController',\r\n },\r\n },\r\n url: '/{pageid:int}?{category:string}',\r\n });\r\n\r\n $urlRouterProvider.otherwise('/1');\r\n } else {\r\n $stateProvider.state('videoList', {\r\n views: {\r\n 'video-list': {\r\n templateUrl: 'video-list.html',\r\n controller: 'VideoListController',\r\n },\r\n },\r\n url: '/{pageid:int}?{category:string}',\r\n });\r\n\r\n $urlRouterProvider.otherwise('/1');\r\n }\r\n};\r\n","import blogRoute from './blog';\r\nimport faqListRoute from './faqList';\r\nimport insightsListRoute from './insightsList';\r\nimport productListRoute from './productList';\r\nimport supportArticlesListRoute from './supportArticlesList';\r\nimport videoListRoute from './videoList';\r\n\r\nconst module = angular.module('ryobi.routes', [])\r\n .config(blogRoute)\r\n .config(faqListRoute)\r\n .config(insightsListRoute)\r\n .config(productListRoute)\r\n .config(supportArticlesListRoute)\r\n .config(videoListRoute);\r\n\r\nexport default module;\r\n","const blogFactory = /* @ngInject */ ($filter, $http, $q) => {\r\n const self = {};\r\n\r\n self.blogPosts = [];\r\n\r\n self.getBlogPosts = () => {\r\n const deferred = $q.defer();\r\n\r\n if (self.blogPosts.length) {\r\n deferred.resolve(self.blogPosts);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/blog/posts/', { params }).then(\r\n (res) => {\r\n self.blogPosts = res.data;\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.getCategories = () => {\r\n const deferred = $q.defer();\r\n\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/blog/categories/', { params }).then(\r\n (res) => {\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.search = (searchQuery) => {\r\n if (!searchQuery || searchQuery.length <= 0) {\r\n return self.getBlogPosts();\r\n }\r\n\r\n const deferred = $q.defer();\r\n\r\n // Get query string parameters.\r\n const params = {\r\n url: location.pathname,\r\n loadSinglePage: true,\r\n searchText: searchQuery,\r\n searchIndex: 'BlogSearchIndex',\r\n };\r\n\r\n $http.get('/api/blog/search/', { params }).then(\r\n (res) => {\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.getFilteredItems = (filters) => {\r\n const deferred = $q.defer();\r\n\r\n self.search(filters.searchQuery).then((data) => {\r\n let filteredItems = data;\r\n\r\n filteredItems = $filter('Category')(filteredItems, filters.categories, 0);\r\n\r\n deferred.resolve(filteredItems);\r\n });\r\n\r\n return deferred.promise;\r\n };\r\n\r\n return self;\r\n};\r\n\r\nexport default blogFactory;\r\n","const categoryFactory = /* @ngInject */ ($filter, $http, $q, storageFactory) => {\r\n const self = {\r\n getCategorySeo,\r\n };\r\n\r\n storageFactory.setSessionItem('categorySeoList', []);\r\n\r\n function getCategorySeo(categoryName) {\r\n const deferred = $q.defer();\r\n\r\n // If no category, return null\r\n if (!categoryName || categoryName.length <= 0) {\r\n deferred.resolve(null);\r\n return deferred.promise;\r\n }\r\n\r\n let categorySeoList;\r\n\r\n // If we have this item in session storage already, return it\r\n const sessionSeoList = storageFactory.getSessionItem('categorySeoList');\r\n\r\n if (sessionSeoList && sessionSeoList.length > 0) {\r\n categorySeoList = JSON.parse(sessionSeoList);\r\n\r\n if (categorySeoList !== null && categoryName in categorySeoList) {\r\n deferred.resolve(categorySeoList[categoryName]);\r\n return deferred.promise;\r\n }\r\n }\r\n\r\n const params = {\r\n categoryName,\r\n };\r\n\r\n $http.get('/api/productcategory/categoryseo/', { params }).then(\r\n (res) => {\r\n if (!categorySeoList) {\r\n categorySeoList = {};\r\n }\r\n\r\n // Store it back into the session\r\n categorySeoList[categoryName] = res.data;\r\n storageFactory.setSessionItem('categorySeoList', JSON.stringify(categorySeoList));\r\n\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n }\r\n\r\n return self;\r\n};\r\n\r\nexport default categoryFactory;\r\n","import filter from 'lodash/filter';\r\nimport find from 'lodash/find';\r\n\r\nconst FaqsFactory = /* @ngInject */ ($filter, $http, $state, $stateParams, $q, loadingBar) => {\r\n let getAllFaqsDefer;\r\n let getAllCategoriesDefer;\r\n\r\n let allFaqs = [];\r\n\r\n const self = {};\r\n self.allCategories = [];\r\n self.filteredItems = [];\r\n self.filters = {};\r\n\r\n /**\r\n * Filters the FAQs to be displayed on the page\r\n */\r\n self.getFilteredItems = () => {\r\n const deferred = $q.defer();\r\n\r\n getCategories()\r\n .then(() => {\r\n searchFaqs(self.filters.searchQuery)\r\n .then((data) => {\r\n // Add a loading bar to make it appear that something's happened\r\n loadingBar.addLoadingBar();\r\n\r\n let filteredItems = data.data;\r\n\r\n const filters = self.filters;\r\n\r\n // Get the selected category - if one isn't set, then it's null (show all)\r\n const selectedCategory = filters.selectedCategory;\r\n\r\n if (selectedCategory) {\r\n filteredItems = filter(filteredItems,\r\n faq => faq.NodeParentId === selectedCategory.NodeId,\r\n );\r\n }\r\n\r\n filters.selectedCategory = selectedCategory;\r\n\r\n setStateParameters();\r\n self.filteredItems = filteredItems;\r\n deferred.resolve(filteredItems);\r\n });\r\n });\r\n\r\n return deferred.promise;\r\n };\r\n\r\n function searchFaqs(searchQuery) {\r\n if (!searchQuery || searchQuery.length <= 0) {\r\n return getAllFaqs();\r\n }\r\n\r\n const deferred = $q.defer();\r\n\r\n // Get query string parameters.\r\n const params = {\r\n url: location.pathname,\r\n loadSinglePage: true,\r\n searchText: searchQuery,\r\n searchIndex: 'FaqSearchIndex',\r\n };\r\n\r\n $http.get('/api/faqs/search/', { params }).then(\r\n (data) => {\r\n deferred.resolve(data);\r\n },\r\n (data) => {\r\n deferred.reject(data);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n }\r\n\r\n function getAllFaqs() {\r\n if (getAllFaqsDefer) {\r\n return getAllFaqsDefer.promise;\r\n }\r\n\r\n getAllFaqsDefer = $q.defer();\r\n\r\n if (allFaqs.length) {\r\n getAllFaqsDefer.resolve(allFaqs);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/faqs/', { params }).then(\r\n (data) => {\r\n allFaqs = data;\r\n getAllFaqsDefer.resolve(data);\r\n },\r\n (data) => {\r\n getAllFaqsDefer.reject(data);\r\n },\r\n );\r\n }\r\n\r\n return getAllFaqsDefer.promise;\r\n }\r\n\r\n function getCategories() {\r\n if (getAllCategoriesDefer) {\r\n return getAllCategoriesDefer.promise;\r\n }\r\n\r\n getAllCategoriesDefer = $q.defer();\r\n\r\n if (self.allCategories.length) {\r\n getAllCategoriesDefer.resolve(self.allCategories);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/faqs/categories/', { params }).then(\r\n (data) => {\r\n self.allCategories = data;\r\n getAllCategoriesDefer.resolve(data);\r\n },\r\n (data) => {\r\n getAllCategoriesDefer.reject(data);\r\n },\r\n );\r\n }\r\n\r\n return getAllCategoriesDefer.promise;\r\n }\r\n\r\n /**\r\n * Sets the state parameters based on the pagination and filter objects.\r\n * @private\r\n */\r\n function setStateParameters() {\r\n const stateParameters = {};\r\n\r\n const filters = self.filters;\r\n if (filters) {\r\n if (filters.selectedCategory) {\r\n stateParameters.category = filters.selectedCategory.Title;\r\n }\r\n\r\n if (filters.searchQuery && filters.searchQuery.length) {\r\n stateParameters.search = filters.searchQuery;\r\n }\r\n }\r\n\r\n $state.go($state.current.name, stateParameters, {\r\n location: 'replace',\r\n inherit: false,\r\n notify: false,\r\n });\r\n }\r\n\r\n self.filters.searchQuery = $stateParams.search || null;\r\n\r\n // Initialisation: Save all categories\r\n getCategories().then((data) => {\r\n // If we have a category state selected, find that category object and store it\r\n self.filters.selectedCategory = find(\r\n data,\r\n category => category.Title === $stateParams.category,\r\n );\r\n\r\n // Then filter the list of all FAQs\r\n self.getFilteredItems();\r\n });\r\n\r\n return self;\r\n};\r\n\r\nexport default FaqsFactory;\r\n","import filter from 'lodash/filter';\r\n\r\nconst insightsFactory = /* @ngInject */ ($filter, $http, $q) => {\r\n let getAllInsightsDefer;\r\n let getAllCategoriesDefer;\r\n\r\n const self = {};\r\n\r\n /** Pagination options. */\r\n self.pagination = {\r\n pageid: 1,\r\n itemsPerPage: 8,\r\n };\r\n\r\n self.allInsights = [];\r\n self.allCategories = [];\r\n self.pagedItems = [];\r\n self.filteredItems = [];\r\n\r\n self.getInsights = () => {\r\n if (getAllInsightsDefer) {\r\n return getAllInsightsDefer.promise;\r\n }\r\n\r\n getAllInsightsDefer = $q.defer();\r\n\r\n if (self.allInsights.length) {\r\n getAllInsightsDefer.resolve(self.allInsights);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/insights/', { params }).then(\r\n (res) => {\r\n self.allInsights = res.data;\r\n getAllInsightsDefer.resolve(res.data);\r\n },\r\n (err) => {\r\n getAllInsightsDefer.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return getAllInsightsDefer.promise;\r\n };\r\n\r\n self.setFilteredItems = () => {\r\n const defer = $q.defer();\r\n\r\n self.getInsights().then((data) => {\r\n self.filteredItems = [];\r\n self.setPagedItems();\r\n let filteredItems = data;\r\n\r\n const filters = self.filters;\r\n if (filters) {\r\n filteredItems = $filter('Category')(filteredItems, filters.categories, 0);\r\n\r\n if (filters.videos) {\r\n filteredItems = filter(filteredItems, insight => insight.HasVideo);\r\n }\r\n }\r\n\r\n self.filteredItems = filteredItems;\r\n self.setPagedItems();\r\n\r\n defer.resolve(self.filteredItems);\r\n });\r\n\r\n return defer.promise;\r\n };\r\n\r\n self.setPagedItems = () => {\r\n const defer = $q.defer();\r\n self.pagedItems = $filter('limitTo')(self.filteredItems, self.pagesize(), 0);\r\n defer.resolve(self.pagedItems);\r\n return defer.promise;\r\n };\r\n\r\n self.getAllCategories = () => {\r\n if (getAllCategoriesDefer) {\r\n return getAllCategoriesDefer.promise;\r\n }\r\n\r\n getAllCategoriesDefer = $q.defer();\r\n\r\n if (self.allCategories.length) {\r\n getAllCategoriesDefer.resolve(self.allCategories);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/insights/Categories/', { params }).then(\r\n (res) => {\r\n self.allCategories = res.data;\r\n getAllCategoriesDefer.resolve(res.data);\r\n },\r\n (err) => {\r\n getAllCategoriesDefer.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return getAllCategoriesDefer.promise;\r\n };\r\n\r\n /**\r\n * Returns the current page size\r\n */\r\n self.pagesize = () => (\r\n self.pagination.itemsPerPage * self.pagination.pageid\r\n );\r\n\r\n return self;\r\n};\r\n\r\nexport default insightsFactory;\r\n","const LoadingBar = /* @ngInject */ (cfpLoadingBar) => {\r\n const self = {};\r\n\r\n self.addLoadingBar = () => {\r\n cfpLoadingBar.start();\r\n setTimeout(() => {\r\n cfpLoadingBar.complete();\r\n }, 500);\r\n };\r\n\r\n return self;\r\n};\r\n\r\nexport default LoadingBar;\r\n","const productComparisonFactory = /* @ngInject */ ($filter, $http, $q) => {\r\n const self = {};\r\n\r\n self.compareChange = (agilityId) => {\r\n const deferred = $q.defer();\r\n\r\n const params = {\r\n agilityId,\r\n };\r\n\r\n $http.get('/api/product/compareChange/', { params }).then(\r\n (data) => {\r\n deferred.resolve(data);\r\n },\r\n (data) => {\r\n deferred.reject(data);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.removeAllComparisons = () => {\r\n const deferred = $q.defer();\r\n\r\n $http.get('/api/product/removeAllComparisons/').then(\r\n (res) => {\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.getCompareSettings = () => {\r\n const deferred = $q.defer();\r\n\r\n $http.get('/api/product/compareSettings/').then(\r\n (res) => {\r\n self.compareSettings = res.data;\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.logCompare = (cultureCode) => {\r\n const deffered = $q.defer();\r\n const params = {\r\n cultureCode,\r\n };\r\n\r\n $http.get('/api/analytics/logcompare/', { params }).then(\r\n () => {},\r\n (err) => {\r\n deffered.reject(err);\r\n },\r\n );\r\n\r\n return deffered.promise;\r\n };\r\n\r\n // Initialise\r\n self.getCompareSettings();\r\n\r\n return self;\r\n};\r\n\r\nexport default productComparisonFactory;\r\n","import filter from 'lodash/filter';\r\nimport some from 'lodash/some';\r\n\r\nconst ProductListFactory = /* @ngInject */ ($filter, $http, $q, storageFactory) => {\r\n const self = {};\r\n\r\n self.products = {};\r\n\r\n self.loaded = false;\r\n\r\n // Links to other categories\r\n self.categoryTypes = null;\r\n\r\n // A list of filtered products\r\n self.filteredItems = null;\r\n\r\n // The filters that have been chosen\r\n self.selectedFilters = null;\r\n\r\n // The filters to display\r\n let filters;\r\n\r\n self.getFilters = () => {\r\n const deferred = $q.defer();\r\n const pageUrl = self.getRouteProxy();\r\n const proxyFilters = self.getProxyFilters();\r\n const additionalFilters = self.getAdditionalFilters();\r\n const groupedFilters = self.getGroupedFilters();\r\n\r\n if (filters) {\r\n deferred.resolve(filters);\r\n return deferred.promise;\r\n }\r\n\r\n const params = {\r\n url: pageUrl,\r\n additionalFilters: [...additionalFilters],\r\n cultureCode: $('#lng').val(),\r\n ...proxyFilters.overrides,\r\n groupedFilters: [...groupedFilters],\r\n };\r\n\r\n $http.post('/api/productcategory/filters/', { ...params }).then(\r\n (res) => {\r\n filters = { ...res.data, ...proxyFilters };\r\n Object.keys(proxyFilters.overrides).forEach((key) => {\r\n filters[key] = proxyFilters.overrides[key];\r\n });\r\n filters.url = self.getRouteProxy();\r\n deferred.resolve(filters);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.getProducts = (filterParams) => {\r\n const deferred = $q.defer();\r\n let key = '';\r\n const proxyFilters = self.getProxyFilters();\r\n const groupedFilters = self.getGroupedFilters();\r\n\r\n // Set grouped filter stuff\r\n if (filterParams.GroupedAll) {\r\n for (let i = 0; i < groupedFilters.length; i += 1) {\r\n if (groupedFilters[i].agilityId === filterParams.GroupedAll) {\r\n groupedFilters[i].selected = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n let searchCode = '';\r\n if (filterParams) {\r\n searchCode = filterParams.productcode;\r\n }\r\n\r\n if (filterParams.category !== undefined && filterParams.category !== null) {\r\n key = `productList|${filterParams.category.Url}`;\r\n } else {\r\n key = 'productList|All';\r\n }\r\n\r\n const sessionList = storageFactory.getSessionItem(key);\r\n if (sessionList && sessionList.length > 0) {\r\n const productList = JSON.parse(sessionList);\r\n deferred.resolve(productList);\r\n } else if (self.products[key]) {\r\n deferred.resolve(self.products[key]);\r\n } else {\r\n const params = {\r\n url: self.getRouteProxy(filterParams.ignoreUrl),\r\n productCode: searchCode,\r\n agilityIds: filterParams.agilityIds,\r\n cultureCode: $('#lng').val(),\r\n ...proxyFilters.overrides,\r\n groupedFilters: [...groupedFilters],\r\n };\r\n\r\n params.additionalFilters = self.getAdditionalFilters();\r\n for (let i = 1; i <= 3; i += 1) {\r\n if (filterParams[`unknown${i}`]) {\r\n if (params.additionalFilters.length >= i - 1) {\r\n params.additionalFilters[i - 1].selectedValue = filterParams[`unknown${i}`];\r\n }\r\n }\r\n }\r\n\r\n if (filterParams.category !== undefined && filterParams.category !== null) {\r\n params.url = filterParams.category.Url;\r\n }\r\n\r\n $http.post('/api/productcategory/productspost/', params).then(\r\n (res) => {\r\n // storageFactory.setSessionItem(key, JSON.stringify(res.data));\r\n deferred.resolve(res.data);\r\n },\r\n (err) => {\r\n deferred.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.getRouteProxy = (ignoreAll) => {\r\n const value = angular.element('.js-listing-proxy').val();\r\n\r\n if (ignoreAll === true) {\r\n return '/';\r\n }\r\n\r\n if (value !== null && value !== '' && value !== undefined) {\r\n return value;\r\n }\r\n\r\n return location.pathname;\r\n };\r\n\r\n self.getProxyFilters = () => {\r\n const value = angular.element('.js-listing-filters').val();\r\n\r\n if (value !== null && value !== '' && value !== undefined) {\r\n return JSON.parse(value);\r\n }\r\n\r\n return {\r\n filterFunctionalityOverrides: [],\r\n hiddenFilters: [],\r\n overrides: { },\r\n };\r\n };\r\n\r\n self.getGroupedFilters = () => {\r\n const value = angular.element('.js-listing-grouped-filters').val();\r\n\r\n if (value !== null && value !== '' && value !== undefined) {\r\n return JSON.parse(value);\r\n }\r\n\r\n return {};\r\n };\r\n\r\n let deferredCategoryTypes;\r\n\r\n self.getCategoryTypes = () => {\r\n if (deferredCategoryTypes) {\r\n return deferredCategoryTypes.promise;\r\n }\r\n\r\n deferredCategoryTypes = $q.defer();\r\n\r\n if (self.categoryTypes) {\r\n deferredCategoryTypes.resolve(self.categoryTypes);\r\n } else {\r\n const params = {\r\n url: self.getRouteProxy(),\r\n };\r\n\r\n $http.get('/api/productcategory/CategoryTypes/', { params }).then(\r\n (res) => {\r\n self.categoryTypes = res.data;\r\n deferredCategoryTypes.resolve(res.data);\r\n },\r\n (err) => {\r\n deferredCategoryTypes.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return deferredCategoryTypes.promise;\r\n };\r\n\r\n self.getAdditionalFilters = () => {\r\n const value = angular.element('.js-listing-additional-filters').val();\r\n if (value !== null && value !== '' && value !== undefined) {\r\n return JSON.parse(value);\r\n }\r\n\r\n return {};\r\n };\r\n\r\n self.getFilteredItems = (filterParams) => {\r\n const deferred = $q.defer();\r\n\r\n self.getProducts(filterParams).then((data) => {\r\n let filteredItems = data;\r\n\r\n // Filter the items based on the selections\r\n if (filterParams) {\r\n // Filter any lists\r\n filteredItems = filterProducts(filteredItems, 'PowerSource', filterParams.powersource);\r\n filteredItems = filterProducts(filteredItems, 'Status', filterParams.status);\r\n\r\n // Filter by how many batteries a product has\r\n filteredItems = filter(filteredItems, (x) => {\r\n if (filterParams.batteries === 'true') {\r\n if (x.NumberOfBatteries > 0) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n if (filterParams.batteries === 'false') {\r\n if (x.NumberOfBatteries <= 0) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n deferred.resolve(filteredItems);\r\n });\r\n\r\n return deferred.promise;\r\n };\r\n\r\n function filterProducts(items, fieldName, filterName) {\r\n if (filterName && filterName.length > 0) {\r\n const f = filterName.toUpperCase();\r\n\r\n items = filter(items, p => some(p[fieldName], (x) => {\r\n if (x.toUpperCase() === f) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }));\r\n }\r\n\r\n return items;\r\n }\r\n\r\n self.initialised = false;\r\n\r\n return self;\r\n};\r\n\r\nexport default ProductListFactory;\r\n","const storageFactory = /* @ngInject */ () => {\r\n const self = {\r\n getItem,\r\n getSessionItem,\r\n setItem,\r\n setSessionItem,\r\n };\r\n\r\n /** Get item from localstorage. */\r\n function getItem(key) {\r\n try {\r\n return localStorage.getItem(key);\r\n } catch (e) {\r\n return null;\r\n }\r\n }\r\n\r\n /** Set item in localstorage. */\r\n function setItem(key, data) {\r\n try {\r\n localStorage.setItem(key, data);\r\n return true;\r\n } catch (e) {\r\n return false;\r\n }\r\n }\r\n\r\n /** Get item from sessionstorage. */\r\n function getSessionItem(key) {\r\n try {\r\n return sessionStorage.getItem(key);\r\n } catch (e) {\r\n return null;\r\n }\r\n }\r\n\r\n /** Set item in sessionstorage. */\r\n function setSessionItem(key, data) {\r\n try {\r\n sessionStorage.setItem(key, data);\r\n return true;\r\n } catch (e) {\r\n return false;\r\n }\r\n }\r\n\r\n return self;\r\n};\r\n\r\nexport default storageFactory;\r\n","import filter from 'lodash/filter';\r\nimport find from 'lodash/find';\r\n\r\nconst supportFactory = /* @ngInject */ ($filter, $http, $state, $stateParams, $q, loadingBar) => {\r\n let getAllArticlesDefer;\r\n let getAllCategoriesDefer;\r\n\r\n let allArticles = [];\r\n\r\n const self = {};\r\n self.allCategories = [];\r\n self.filteredItems = [];\r\n\r\n self.filters = {};\r\n\r\n /**\r\n * Filters the articles to be displayed on the page\r\n */\r\n self.getFilteredItems = () => {\r\n const deferred = $q.defer();\r\n\r\n getCategories().then(() => {\r\n getAllArticles().then((data) => {\r\n // Add a loading bar to make it appear that something's happened\r\n loadingBar.addLoadingBar();\r\n\r\n let filteredItems = data;\r\n\r\n const filters = self.filters;\r\n\r\n // Get the selected category, using the first one if not set\r\n const selectedCategory = filters.selectedCategory || self.allCategories[0];\r\n\r\n if (selectedCategory) {\r\n filteredItems = filter(\r\n filteredItems,\r\n article => article.NodeParentId === selectedCategory.NodeId,\r\n );\r\n }\r\n\r\n filters.selectedCategory = selectedCategory;\r\n\r\n setStateParameters();\r\n self.filteredItems = filteredItems;\r\n deferred.resolve(filteredItems);\r\n });\r\n });\r\n\r\n return deferred.promise;\r\n };\r\n\r\n function getAllArticles() {\r\n if (getAllArticlesDefer) {\r\n return getAllArticlesDefer.promise;\r\n }\r\n\r\n getAllArticlesDefer = $q.defer();\r\n\r\n if (allArticles.length) {\r\n getAllArticlesDefer.resolve(allArticles);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/support/articles', { params }).then(\r\n (res) => {\r\n allArticles = res.data;\r\n getAllArticlesDefer.resolve(res.data);\r\n },\r\n (err) => {\r\n getAllArticlesDefer.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return getAllArticlesDefer.promise;\r\n }\r\n\r\n function getCategories() {\r\n if (getAllCategoriesDefer) {\r\n return getAllCategoriesDefer.promise;\r\n }\r\n\r\n getAllCategoriesDefer = $q.defer();\r\n\r\n if (self.allCategories.length) {\r\n getAllCategoriesDefer.resolve(self.allCategories);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/support/categories/', { params }).then(\r\n (res) => {\r\n self.allCategories = res.data;\r\n getAllCategoriesDefer.resolve(res.data);\r\n },\r\n (err) => {\r\n getAllCategoriesDefer.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return getAllCategoriesDefer.promise;\r\n }\r\n\r\n /**\r\n * Sets the state parameters based on the pagination and filter objects.\r\n * @private\r\n */\r\n function setStateParameters() {\r\n const stateParameters = {};\r\n\r\n const filters = self.filters;\r\n if (filters) {\r\n if (filters.selectedCategory) {\r\n stateParameters.category = filters.selectedCategory.Title;\r\n }\r\n }\r\n\r\n $state.go($state.current.name, stateParameters, {\r\n location: 'replace',\r\n inherit: false,\r\n notify: false,\r\n });\r\n }\r\n\r\n // Initialisation: Save all categories\r\n getCategories().then((data) => {\r\n // If we have a category state selected, find that category object and store it\r\n self.filters.selectedCategory = find(\r\n data,\r\n category => category.Title === $stateParams.category,\r\n );\r\n\r\n // Then filter the list of all articles\r\n self.getFilteredItems();\r\n });\r\n\r\n return self;\r\n};\r\n\r\nexport default supportFactory;\r\n","const videoListFactory = /* @ngInject */ ($filter, $http, $q) => {\r\n let getVideosDefer;\r\n let getAllCategoriesDefer;\r\n\r\n const self = {};\r\n\r\n /** Pagination options. */\r\n self.pagination = {\r\n pageid: 1,\r\n itemsPerPage: 6,\r\n };\r\n\r\n self.videos = [];\r\n self.filteredItems = [];\r\n\r\n self.getVideos = () => {\r\n if (getVideosDefer) {\r\n return getVideosDefer.promise;\r\n }\r\n\r\n getVideosDefer = $q.defer();\r\n\r\n if (self.videos.length) {\r\n getVideosDefer.resolve(self.videos);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n };\r\n\r\n $http.get('/api/video/', { params }).then(\r\n (res) => {\r\n self.videos = res.data;\r\n getVideosDefer.resolve(res.data);\r\n },\r\n (err) => {\r\n getVideosDefer.reject(err);\r\n },\r\n );\r\n }\r\n\r\n return getVideosDefer.promise;\r\n };\r\n\r\n /**\r\n * Filters the products to be displayed on the page\r\n */\r\n self.setFilteredItems = () => {\r\n const deferred = $q.defer();\r\n\r\n self.getVideos().then((data) => {\r\n let filteredItems = data;\r\n\r\n const filters = self.filters;\r\n\r\n if (filters) {\r\n filteredItems = $filter('Category')(filteredItems, filters.categories, 0);\r\n }\r\n\r\n self.filteredItems = filteredItems;\r\n deferred.resolve(filteredItems);\r\n });\r\n\r\n return deferred.promise;\r\n };\r\n\r\n self.getAllCategories = () => {\r\n if (getAllCategoriesDefer) {\r\n return getAllCategoriesDefer.promise;\r\n }\r\n\r\n getAllCategoriesDefer = $q.defer();\r\n\r\n if (self.allCategories) {\r\n getAllCategoriesDefer.resolve(self.allCategories);\r\n } else {\r\n const params = {\r\n url: location.pathname,\r\n culture: $('#lng').val(),\r\n };\r\n\r\n $http.get('/api/Video/Categories/', { params }).then(\r\n (data) => {\r\n self.allCategories = data;\r\n getAllCategoriesDefer.resolve(data);\r\n },\r\n (data) => {\r\n getAllCategoriesDefer.reject(data);\r\n },\r\n );\r\n }\r\n\r\n return getAllCategoriesDefer.promise;\r\n };\r\n\r\n return self;\r\n};\r\n\r\nexport default videoListFactory;\r\n","import blogFactory from './blogFactory';\r\nimport categoryFactory from './categoryFactory';\r\nimport faqsFactory from './faqsFactory';\r\nimport insightsFactory from './insightsFactory';\r\nimport loadingBar from './loadingBar';\r\nimport productComparisonFactory from './productComparisonFactory';\r\nimport productListFactory from './productListFactory';\r\nimport storageFactory from './storageFactory';\r\nimport supportFactory from './supportFactory';\r\nimport videoListFactory from './videoListFactory';\r\n\r\nconst module = angular.module('ryobi.services', [])\r\n .factory('blogFactory', blogFactory)\r\n .factory('categoryFactory', categoryFactory)\r\n .factory('faqsFactory', faqsFactory)\r\n .factory('insightsFactory', insightsFactory)\r\n .factory('loadingBar', loadingBar)\r\n .factory('productComparisonFactory', productComparisonFactory)\r\n .factory('productListFactory', productListFactory)\r\n .factory('storageFactory', storageFactory)\r\n .factory('supportFactory', supportFactory)\r\n .factory('videoListFactory', videoListFactory);\r\n\r\nexport default module;\r\n","export default class WTTRootController {\r\n /* @ngInject */\r\n constructor($log, $rootScope, $translate, WTTService) {\r\n this.$log = $log;\r\n this.wttService = WTTService;\r\n\r\n // Show content after translations have loaded.\r\n this.visible = $translate.isReady();\r\n $translate.onReady(() => {\r\n this.visible = true;\r\n });\r\n }\r\n $onInit() {\r\n const { $log, wttService } = this;\r\n\r\n try {\r\n const $initialData = angular.element('[id$=\"hdnWTTInitialData\"]');\r\n const initialData = JSON.parse($initialData.val());\r\n wttService.setFormData(initialData);\r\n } catch (err) {\r\n $log.error(err);\r\n }\r\n }\r\n}\r\n","import controller from './controller';\r\nimport template from './template.html';\r\n\r\nexport default {\r\n controller,\r\n template,\r\n};\r\n","/* eslint-disable no-useless-constructor */\r\nexport default class wttIntroController {\r\n /* @ngInject */\r\n constructor($state, WTTService) {\r\n // default\r\n this.wttService = WTTService;\r\n this.formData = this.wttService.formData;\r\n }\r\n}\r\n","import template from './template.html';\r\nimport controller from './controller';\r\n\r\nexport default {\r\n template,\r\n controller,\r\n};\r\n","export default class WTTGameController {\r\n /* @ngInject */\r\n constructor($state, WTTService) {\r\n this.$state = $state;\r\n this.wttService = WTTService;\r\n\r\n // Binding Content Editable Data to the scope\r\n this.formData = this.wttService.formData;\r\n }\r\n\r\n $onInit() {\r\n this.tileCount = 0;\r\n this.tileLimit = 3;\r\n }\r\n get showNavBar() {\r\n return (this.tileCount >= this.tileLimit);\r\n }\r\n onTileSelect($event) {\r\n if ((++this.tileCount) > this.tileLimit) { // eslint-disable-line\r\n return;\r\n }\r\n\r\n const $tile = angular.element($event.target);\r\n $tile.addClass('selected');\r\n }\r\n onSubmit($event, form, formData) {\r\n const { wttService, $state } = this;\r\n\r\n if ($event) {\r\n $event.preventDefault();\r\n }\r\n\r\n if (form.$invalid) {\r\n form.$setSubmitted();\r\n return;\r\n }\r\n\r\n wttService.setFormData(formData).then(\r\n () => wttService.setSubmission(formData).then(\r\n () => $state.go('wtt.more'),\r\n () => angular.noop,\r\n ),\r\n () => angular.noop,\r\n );\r\n }\r\n\r\n onTermsClick(val) {\r\n const termsToShow = angular.element(`.js-full-screen-popup[data-popup=\"wtt-terms-${val}\"]`);\r\n if (termsToShow.length) {\r\n angular.element('html').addClass('stop-scroll');\r\n angular.element('html').addClass('full-screen-popup-open');\r\n termsToShow.addClass('is-active');\r\n }\r\n }\r\n onTermsHideClick(val) {\r\n const termsToHide = angular.element(`.js-full-screen-popup[data-popup=\"wtt-terms-${val}\"]`);\r\n if (termsToHide.length) {\r\n angular.element('html').removeClass('stop-scroll');\r\n angular.element('html').removeClass('full-screen-popup-open');\r\n termsToHide.removeClass('is-active');\r\n }\r\n }\r\n}\r\n","import controller from './controller';\r\nimport template from './template.html';\r\n\r\nexport default {\r\n controller,\r\n template,\r\n};\r\n","export default class WTTSubmissionController {\r\n /* @ngInject */\r\n constructor($state, WTTService) {\r\n this.$state = $state;\r\n this.wttService = WTTService;\r\n this.formData = this.wttService.formData;\r\n }\r\n onSubmit($event, form, formData) {\r\n const { wttService, $state } = this;\r\n\r\n if ($event) {\r\n $event.preventDefault();\r\n }\r\n\r\n if (form.$invalid) {\r\n form.$setSubmitted();\r\n return;\r\n }\r\n\r\n wttService.setFormData(formData).then(\r\n () => wttService.setSubmission(formData).then(\r\n () => $state.go('wtt.more'),\r\n () => angular.noop,\r\n ),\r\n () => angular.noop,\r\n );\r\n }\r\n}\r\n","import controller from './controller';\r\nimport template from './template.html';\r\n\r\nexport default {\r\n controller,\r\n template,\r\n};\r\n","import template from './template.html';\r\n\r\nexport default {\r\n template,\r\n};\r\n","export default class WTTMoreController {\r\n /* @ngInject */\r\n constructor($state, WTTService) {\r\n this.$state = $state;\r\n this.wttService = WTTService;\r\n\r\n // Binding Content Editable Data to the scope\r\n this.formData = this.wttService.formData;\r\n }\r\n\r\n setQuestionAnswer($event) {\r\n const questionIndex = $event.questionIndex;\r\n const answerIndex = $event.answerIndex;\r\n\r\n const answers = this.formData.dynamicFormQuestions[questionIndex].answers;\r\n for (let i = 0; i < answers.length; i += 1) {\r\n if (i === answerIndex) {\r\n answers[i].isAnswered = true;\r\n } else {\r\n answers[i].isAnswered = false;\r\n }\r\n }\r\n }\r\n\r\n onSubmit() {\r\n this.wttService.setFormData(this.formData).then(\r\n () => this.wttService.setFinalStepData(this.formData.dynamicFormQuestions).then(\r\n () => this.$state.go('wtt.confirmation'),\r\n () => angular.noop,\r\n ),\r\n () => angular.noop,\r\n );\r\n }\r\n}\r\n","import controller from './controller';\r\nimport template from './template.html';\r\n\r\nexport default {\r\n template,\r\n controller,\r\n};\r\n","import template from './template.html';\r\n\r\nexport default {\r\n bindings: {\r\n onSubmit: '&',\r\n onTermsClick: '&',\r\n onTermsHideClick: '&',\r\n },\r\n template,\r\n};\r\n","/* eslint-disable no-useless-constructor */\r\nexport default class WTTImageGridController {\r\n /* @ngInject */\r\n constructor() {\r\n // default\r\n }\r\n get viewbox() {\r\n return `0 0 ${this.width} ${this.height}`;\r\n }\r\n $onChanges() {\r\n // Set tile dimensions - this are calculated as fractions of 1 for scaling.\r\n this.tileWidth = (1 / this.horizontal);\r\n this.tileHeight = (1 / this.vertical);\r\n\r\n // Create array of tiles.\r\n this.dividers = this.generateDividers();\r\n this.tiles = this.generateTiles();\r\n }\r\n generateDividers() {\r\n const dividers = [];\r\n\r\n // Vertical dividers.\r\n for (let x = 1; x < this.horizontal; x += 1) {\r\n const xPos = (x * this.tileWidth * 100);\r\n dividers.push({\r\n x1: `${xPos}%`,\r\n x2: `${xPos}%`,\r\n y1: '0%',\r\n y2: '100%',\r\n });\r\n }\r\n\r\n // Horizontal dividers.\r\n for (let y = 1; y < this.vertical; y += 1) {\r\n const yPos = (y * this.tileHeight * 100);\r\n dividers.push({\r\n x1: '0%',\r\n x2: '100%',\r\n y1: `${yPos}%`,\r\n y2: `${yPos}%`,\r\n });\r\n }\r\n\r\n return dividers;\r\n }\r\n generateTiles() {\r\n const tiles = [];\r\n\r\n for (let y = 0; y < this.vertical; y += 1) {\r\n for (let x = 0; x < this.horizontal; x += 1) {\r\n const xPos = (x * this.tileWidth);\r\n const yPos = (y * this.tileHeight);\r\n tiles.push({\r\n id: `${x}-${y}`,\r\n x: xPos,\r\n xPercent: `${xPos * 100}%`,\r\n y: yPos,\r\n yPercent: `${yPos * 100}%`,\r\n width: this.tileWidth,\r\n widthPercent: `${this.tileWidth * 100}%`,\r\n height: this.tileHeight,\r\n heightPercent: `${this.tileHeight * 100}%`,\r\n });\r\n }\r\n }\r\n\r\n return tiles;\r\n }\r\n}\r\n","import controller from './controller';\r\nimport template from './template.html';\r\n\r\nexport default {\r\n bindings: {\r\n onTileSelect: '&',\r\n width: '<',\r\n height: '<',\r\n horizontal: '<',\r\n vertical: '<',\r\n src: '<',\r\n },\r\n controller,\r\n template,\r\n};\r\n","/* eslint-disable no-useless-constructor */\r\nexport default class wttDynamicFormControl {\r\n /* @ngInject */\r\n constructor($state, WTTService) {\r\n // default\r\n this.wttService = WTTService;\r\n this.formData = this.wttService.formData;\r\n }\r\n}\r\n","import controller from './controller';\r\nimport template from './template.html';\r\n\r\nexport default {\r\n bindings: {\r\n question: '<',\r\n answer: '<',\r\n questionIndex: '<',\r\n answerIndex: '<',\r\n formData: '<',\r\n onSubmit: '&',\r\n setQuestionAnswer: '&',\r\n },\r\n controller,\r\n template,\r\n};\r\n","export default class WTTService {\r\n /* @ngInject */\r\n constructor($http, $log) {\r\n this.$http = $http;\r\n this.$log = $log;\r\n this.formData = {};\r\n }\r\n /** Set internal form data. */\r\n setFormData(formData) {\r\n this.formData = {\r\n ...this.formData,\r\n ...formData,\r\n };\r\n return Promise.resolve(this.formData);\r\n }\r\n /** Post submission form data. */\r\n setSubmission() {\r\n const { $http, $log } = this;\r\n\r\n return $http.post('/api/wtt/submissions', this.formData).then(\r\n (res) => {\r\n $log.info(res);\r\n return Promise.resolve(res);\r\n },\r\n (err) => {\r\n $log.error(err);\r\n return Promise.reject(err);\r\n },\r\n );\r\n }\r\n\r\n /** Post final step data. */\r\n setFinalStepData() {\r\n const { $http, $log } = this;\r\n\r\n return $http.post('/api/wtt/finalstep', this.formData.dynamicFormQuestions).then(\r\n (res) => {\r\n $log.info(res);\r\n return Promise.resolve(res);\r\n },\r\n (err) => {\r\n $log.error(err);\r\n return Promise.reject(err);\r\n },\r\n );\r\n }\r\n}\r\n","import 'angular';\r\nimport WebFont from 'webfontloader';\r\n\r\n// Routes.\r\nimport wttRoot from './wtt-root';\r\nimport wttIntro from './wtt-intro';\r\nimport wttGame from './wtt-game';\r\nimport wttSubmission from './wtt-submission';\r\nimport wttConfirmation from './wtt-confirmation';\r\nimport wttMore from './wtt-more';\r\n\r\n// Components.\r\nimport wttForm from './wtt-form';\r\nimport wttImageGrid from './wtt-image-grid';\r\nimport wttDynamicFormControl from './wtt-dynamic-form-control';\r\n\r\n// Service.\r\nimport WTTService from './wtt.service';\r\n\r\nexport default angular\r\n .module('ryobi.wtt', [])\r\n // Routes.\r\n .component('wttRoot', wttRoot)\r\n .component('wttIntro', wttIntro)\r\n .component('wttGame', wttGame)\r\n .component('wttSubmission', wttSubmission)\r\n .component('wttConfirmation', wttConfirmation)\r\n .component('wttMore', wttMore)\r\n // Components.\r\n .component('wttForm', wttForm)\r\n .component('wttImageGrid', wttImageGrid)\r\n .component('wttDynamicFormControl', wttDynamicFormControl)\r\n // Service.\r\n .service('WTTService', WTTService)\r\n // Configuration.\r\n .config(configureModule);\r\n\r\n/** Handle module initialisation. */\r\nfunction configureModule($stateProvider, $urlRouterProvider) {\r\n const $container = angular.element('#wtt');\r\n\r\n if (!$container.length) {\r\n return;\r\n }\r\n\r\n require.ensure(['fonts/rockout-rg/rockout-rg.css'], () => {\r\n WebFont.load({\r\n custom: {\r\n families: ['rockout-rg'],\r\n urls: [require('fonts/rockout-rg/rockout-rg.css')],\r\n },\r\n });\r\n });\r\n\r\n $stateProvider\r\n .state('wtt', {\r\n abstract: true,\r\n views: {\r\n main: {\r\n template: '
',\r\n },\r\n },\r\n })\r\n .state('wtt.intro', {\r\n url: '/intro',\r\n views: {\r\n '': {\r\n template: '
',\r\n },\r\n },\r\n })\r\n .state('wtt.game', {\r\n url: '/game',\r\n views: {\r\n '': {\r\n template: '
',\r\n },\r\n },\r\n })\r\n .state('wtt.submission', {\r\n url: '/submission',\r\n views: {\r\n '': {\r\n template: '
',\r\n },\r\n },\r\n })\r\n .state('wtt.more', {\r\n url: '/more',\r\n views: {\r\n '': {\r\n template: \"
\",\r\n },\r\n },\r\n })\r\n .state('wtt.confirmation', {\r\n url: '/confirmation',\r\n views: {\r\n '': {\r\n template: '
',\r\n },\r\n },\r\n });\r\n\r\n $urlRouterProvider.otherwise('/intro');\r\n}\r\n","// Load external libraries\r\nimport 'angular';\r\nimport 'angular-animate';\r\nimport 'angular-cookies';\r\nimport 'angular-loading-bar';\r\nimport 'angular-sanitize';\r\nimport 'angular-translate';\r\nimport 'angular-translate-handler-log';\r\nimport 'angular-translate-storage-cookie';\r\nimport 'angular-translate-storage-local';\r\nimport 'angular-ui-router';\r\nimport 'chosen';\r\nimport 'ng-infinite-scroll';\r\n\r\nimport deferredBootstrapper from 'angular-deferred-bootstrap';\r\n\r\n// Load local vendor libraries\r\nimport './vendor/angular-chosen';\r\nimport './vendor/angular-masonry';\r\nimport './vendor/angular-vertilize';\r\n\r\n// Load angular modules\r\nimport ControllersModule from './controllers';\r\nimport CordlessModule from './cordless';\r\nimport DirectivesModule from './directives';\r\nimport FiltersModule from './filters';\r\nimport LocalisationModule from './localisation';\r\nimport RoutesModule from './routes';\r\nimport ServicesModule from './services';\r\nimport WTTModule from './wtt';\r\n\r\nconst module = angular\r\n .module('ryobi', [\r\n 'ngAnimate',\r\n 'ngCookies',\r\n 'ngSanitize',\r\n 'angular-chosen',\r\n 'angular-loading-bar',\r\n 'infinite-scroll',\r\n 'pascalprecht.translate',\r\n 'ui.router',\r\n 'wu.masonry',\r\n ControllersModule.name,\r\n DirectivesModule.name,\r\n FiltersModule.name,\r\n LocalisationModule.name,\r\n RoutesModule.name,\r\n ServicesModule.name,\r\n CordlessModule.name,\r\n WTTModule.name,\r\n ])\r\n .config(configureModule)\r\n .run(runModule);\r\n\r\n// Set application settings.\r\nmodule.constant('appSettings', {\r\n debugMode: false,\r\n});\r\n\r\ndeferredBootstrapper.bootstrap({\r\n element: document.body,\r\n module: 'ryobi',\r\n resolve: {},\r\n});\r\n\r\n/**\r\n * Configure the module.\r\n * @ngInject\r\n */\r\nfunction configureModule($compileProvider, $httpProvider, $locationProvider) {\r\n $compileProvider.debugInfoEnabled(process.env.NODE_ENV !== 'production');\r\n $httpProvider.useApplyAsync(true);\r\n $locationProvider.html5Mode(false).hashPrefix('!');\r\n}\r\n\r\n/**\r\n * Run the module.\r\n * @ngInject\r\n */\r\nfunction runModule($rootScope) {\r\n // eslint-disable-next-line max-len\r\n if (process.env.NODE_ENV === 'development') {\r\n // Prevent errors being swallowed by ui-router in dev environments.\r\n $rootScope.$on(\r\n '$stateChangeError',\r\n (event, toState, toParams, fromState, fromParams, error) => {\r\n console.error('$stateChangeError', error); // eslint-disable-line no-console\r\n },\r\n );\r\n }\r\n}\r\n","module.exports = \"
0\\\">
![{{vm.title}}]()
0\\\"/>
0, 'col-xs-12 text-align-center': vm.imageSrc.length === 0 }\\\">
{{vm.title}}
\";","module.exports = \"
\";","module.exports = \"
0}\\\">

0\\\"/>
![]()
0\\\" src={{image}} class=\\\"wtt-intro__landing-image wtt-intro__landing-image--{{$index}}\\\"/>
custom.wtt.intro.title
custom.wtt.intro.content
custom.wtt.intro.link \";","module.exports = \"
custom.wtt.game.title
custom.wtt.game.content
\";","module.exports = \"
custom.wtt.submission.title
\";","module.exports = \"
custom.wtt.confirmation.title
custom.WTT.Tracking \";","module.exports = \"
\";","module.exports = \"
\";","module.exports = \"
\";","module.exports = \"
\";"],"sourceRoot":""}