{"version":3,"sources":["webpack://@srexi/purecounterjs/./js/purecounter_vanilla.js"],"names":["registerEventListeners","elements","document","querySelectorAll","window","IntersectionObserverEntry","prototype","intersectObserver","IntersectionObserver","animateElements","forEach","element","observe","addEventListener","animateLegacy","e","parseConfig","legacy","elementIsInView","observer","elm","target","elementConfig","duration","innerHTML","formatNumber","end","intersectionRatio","value","start","setTimeout","config","incrementsPerStep","delay","countMode","currentCount","parseValue","once","setAttribute","counterWorker","setInterval","nextNum","number","steps","mode","parseFloat","nextNumber","clearInterval","startCounter","configValues","filter","call","attributes","attr","test","name","replace","toLowerCase","parseInt","Object","assign","decimals","currency","currencysymbol","separator","separatorsymbol","strConfig","minimumFractionDigits","maximumFractionDigits","RegExp","applySeparator","symbol","limit","Math","abs","Number","toFixed","convertToCurrencySystem","toLocaleString","undefined","data","top","offsetTop","left","offsetLeft","width","offsetWidth","height","offsetHeight","offsetParent","pageYOffset","pageXOffset","innerHeight","innerWidth"],"mappings":"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","file":"/dist/purecounter_vanilla.js","sourcesContent":["/** Initial function */\nfunction registerEventListeners() {\n /** Get all elements with class 'purecounter' */\n var elements = document.querySelectorAll('.purecounter');\n /** Get browser Intersection Listener Support */\n var intersectionSupported = intersectionListenerSupported();\n\n /** Run animateElements base on Intersection Support */\n if (intersectionSupported) {\n var intersectObserver = new IntersectionObserver(animateElements, {\n \"root\": null,\n \"rootMargin\": '20px',\n \"threshold\": 0.5\n });\n\n elements.forEach(element => {intersectObserver.observe(element);})\n } else {\n if (window.addEventListener) {\n animateLegacy(elements);\n\n window.addEventListener('scroll', function(e) {\n animateLegacy(elements);\n }, { \"passive\": true });\n }\n }\n}\n\n/** This legacy to make Purecounter use very lightweight & fast */\nfunction animateLegacy(elements) {\n elements.forEach(element => {\n var config = parseConfig(element);\n if(config.legacy === true && elementIsInView(element)) {\n animateElements([element]);\n }\n })\n}\n\n/** Main Element Count Animation */\nfunction animateElements(elements, observer) {\n elements.forEach(element => {\n var elm = element.target || element; // Just make sure which element will be used\n var elementConfig = parseConfig(elm); // Get config value on that element\n\n // If duration is less than or equal zero, just format the 'end' value\n if (elementConfig.duration <= 0) {\n return elm.innerHTML = formatNumber(elementConfig.end, elementConfig);\n }\n\n if ((!observer && !elementIsInView(element)) || (observer && element.intersectionRatio < 0.5)) {\n var value = elementConfig.start > elementConfig.end ? elementConfig.end : elementConfig.start;\n return elm.innerHTML = formatNumber(value, elementConfig);\n }\n\n // If duration is more than 0, then start the counter\n setTimeout(() => {\n return startCounter(elm, elementConfig);\n }, elementConfig.delay);\n });\n}\n\n/** This is the the counter method */\nfunction startCounter(element, config) {\n // First, get the increments step\n var incrementsPerStep = (config.end - config.start) / (config.duration / config.delay);\n // Next, set the counter mode (Increment or Decrement)\n var countMode = 'inc';\n\n // Set mode to 'decrement' and 'increment step' to minus if start is larger than end\n if (config.start > config.end) {\n countMode = 'dec';\n incrementsPerStep *= -1;\n }\n\n // Next, determine the starting value\n var currentCount = parseValue(config.start);\n // And then print it's value to the page\n element.innerHTML = formatNumber(currentCount, config);\n\n // If the config 'once' is true, then set the 'duration' to 0\n if(config.once === true){\n element.setAttribute('data-purecounter-duration', 0);\n }\n\n // Now, start counting with counterWorker using Interval method based on delay\n var counterWorker = setInterval(() => {\n // First, determine the next value base on current value, increment value, and count mode\n var nextNum = nextNumber(currentCount, incrementsPerStep, countMode);\n // Next, print that value to the page\n element.innerHTML = formatNumber(nextNum, config);\n // Now set that value to the current value, because it's already printed\n currentCount = nextNum;\n\n // If the value is larger or less than the 'end' (base on mode), then print the end value and stop the Interval\n if ((currentCount >= config.end && countMode == 'inc') || (currentCount <= config.end && countMode == 'dec')) {\n element.innerHTML = formatNumber(config.end, config);\n clearInterval(counterWorker);\n }\n }, config.delay);\n}\n\n/** This function is to generate the element Config */\nfunction parseConfig(element) {\n // First, we need to declare the base Config\n // This config will be used if the element doesn't have config\n var baseConfig = {\n start: 0,\n end: 9001,\n duration: 2000,\n delay: 10,\n once: true,\n decimals: 0,\n legacy: true,\n currency: false,\n currencysymbol: false,\n separator: false,\n separatorsymbol: ','\n };\n\n // Next, get all 'data-precounter' attributes value. Store to array\n var configValues = [].filter.call(element.attributes, function(attr) {\n return /^data-purecounter-/.test(attr.name);\n });\n\n // Now, we create element config as an empty object\n var elementConfig = {};\n\n // And then, fill the element config based on config values\n configValues.forEach(e => {\n var name = e.name.replace('data-purecounter-', '').toLowerCase();\n var value = name == 'duration' ? parseInt(parseValue(e.value) * 1000) : parseValue(e.value);\n elementConfig[name] = value; // We will get an object\n })\n\n // Last marge base config with element config and return it as an object\n return Object.assign(baseConfig, elementConfig);\n}\n\n/** This function is to get the next number */\nfunction nextNumber(number, steps, mode = 'inc') {\n // First, get the exact value from the number and step (int or float)\n number = parseValue(number);\n steps = parseValue(steps);\n\n // Last, get the next number based on current number, increment step, and count mode\n // Always return it as float\n return parseFloat(mode === 'inc' ? (number + steps) : (number - steps));\n}\n\n/** This function is to convert number into currency format */\nfunction convertToCurrencySystem (number, config) {\n var symbol = config.currencysymbol || \"\", // Set the Currency Symbol (if any)\n limit = config.decimals || 1, // Set the decimal limit (default is 1)\n number = Math.abs(Number(number)); // Get the absolute value of number\n\n // Set the value\n var value = number >= 1.0e+12 ? `${(number / 1.0e+12).toFixed(limit)} T` // Twelve zeros for Trillions\n : number >= 1.0e+9 ? `${(number / 1.0e+9).toFixed(limit)} B` // Nine zeros for Billions\n : number >= 1.0e+6 ? `${(number / 1.0e+6).toFixed(limit)} M` // Six zeros for Millions\n : number >= 1.0e+3 ? `${(number / 1.0e+12).toFixed(limit)} K` // Three zeros for Thousands\n : number.toFixed(limit); // If less than 1000, print it's value\n\n // Apply symbol before the value and return it as string\n return symbol + value;\n}\n\n/** This function is to get the last formated number */\nfunction applySeparator(value, config){\n // If config separator is false, delete all separator\n if (!config.separator) {\n return value.replace(new RegExp(/,/gi, 'gi'), '')\n }\n\n // If config separator is true, then create separator\n return value.replace(/(\\d)(?=(\\d{3})+(?!\\d))/g, \"$1,\")\n .replace(new RegExp(/,/gi, 'gi'), config.separatorsymbol)\n}\n\n/** This function is to get formated number to be printed in the page */\nfunction formatNumber(number, config) {\n // This is the configuration for 'toLocaleString' method\n var strConfig = {minimumFractionDigits: config.decimals, maximumFractionDigits: config.decimals};\n // Set the number if it using currency, then convert. If doesn't, just parse it as float\n number = config.currency ? convertToCurrencySystem(number, config) : parseFloat(number);\n\n // Last, apply the number separator using number as string\n return applySeparator(number.toLocaleString(undefined, strConfig), config);\n}\n\n/** This function is to get the parsed value */\nfunction parseValue(data) {\n // If number with dot (.), will be parsed as float\n if (/^[0-9]+\\.[0-9]+$/.test(data)) {\n return parseFloat(data);\n }\n // If just number, will be parsed as integer\n if (/^[0-9]+$/.test(data)) {\n return parseInt(data);\n }\n // If it's boolean string, will be parsed as boolean\n if (/^true|false/i.test(data)) {\n return /^true/i.test(data);\n }\n // Return it's value as default\n return data;\n}\n\n// This function is to detect the element is in view or not.\nfunction elementIsInView(element) {\n var top = element.offsetTop;\n var left = element.offsetLeft;\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n while (element.offsetParent) {\n element = element.offsetParent;\n top += element.offsetTop;\n left += element.offsetLeft;\n }\n\n return (\n top >= window.pageYOffset &&\n left >= window.pageXOffset &&\n (top + height) <= (window.pageYOffset + window.innerHeight) &&\n (left + width) <= (window.pageXOffset + window.innerWidth)\n );\n}\n\n/** Just some condition to check browser Intersection Support */\nfunction intersectionListenerSupported() {\n return ('IntersectionObserver' in window) &&\n ('IntersectionObserverEntry' in window) &&\n ('intersectionRatio' in window.IntersectionObserverEntry.prototype);\n}\n\n/** Run the initial function */\n(function () {\n registerEventListeners();\n})();"],"sourceRoot":""}