diff --git a/.eslintignore b/.eslintignore index 2f263929..08cbf405 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,4 @@ -lib/countly.min.js +lib plugin/boomerang/boomerang.min.js examples/ node_modules diff --git a/CHANGELOG.md b/CHANGELOG.md index e2bc6dce..6da2fbb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ -## X.X.X +## 23.12.0 - You can now provide custom storage methods to the SDK +- You can now use the SDK in web workers +- From this version on the SDK is bundled from the Countly JavaScript SDK ## 23.6.3 - You can now add segmentation while presenting a widget with 'present_feedback_widget' diff --git a/README.md b/README.md index f6ccca85..0d963d5d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ # Countly Web SDK +This SDK is bundled from the modular [Countly JavaScript SDK](https://github.com/Countly/countly-sdk-js). + This repository contains the Countly Web SDK, which can be integrated into websites and web applications. The Countly Web SDK is intended to be used with [Countly Lite](https://countly.com/lite), [Countly Flex](https://countly.com/flex) [Countly Enterprise](https://countly.com/enterprise). ## What is Countly? diff --git a/cypress/fixtures/click_test.html b/cypress/fixtures/click_test.html index bca3ef33..1e5e3b04 100644 --- a/cypress/fixtures/click_test.html +++ b/cypress/fixtures/click_test.html @@ -19,7 +19,7 @@ var domEl = queryExtractor(window.location.search).dom; Countly.init({ app_key: "YOUR_APP_KEY", - url: "https://your.domain.count.ly", + url: "https://your.domain.countly", debug: true, test_mode: true }) diff --git a/cypress/fixtures/multi_instance.html b/cypress/fixtures/multi_instance.html index fa9ddacb..b3deb9bd 100644 --- a/cypress/fixtures/multi_instance.html +++ b/cypress/fixtures/multi_instance.html @@ -22,7 +22,7 @@ //initializing first instance, which will be global Countly Countly.init({ app_key: "YOUR_APP_KEY1", - url: "https://your.domain.count.ly", + url: "https://your.domain.countly", test_mode: true }) Countly.remove_consent(); @@ -57,7 +57,7 @@ //initialize second instance for another app synchronously var Countly2 = Countly.init({ app_key: "YOUR_APP_KEY2", //must have different APP key - url: "https://your.domain.count.ly", + url: "https://your.domain.countly", test_mode: true }); @@ -94,7 +94,7 @@ //initialize third instance for another app asynchronously Countly.q.push(["init", { app_key: "YOUR_APP_KEY3", //must have different APP key - url: "https://your.domain.count.ly", + url: "https://your.domain.countly", test_mode: true }]) @@ -128,7 +128,7 @@ //initialize fourth instance for another app asynchronously Countly.q.push(["init", { app_key: "YOUR_APP_KEY4", //must have different APP key - url: "https://your.domain.count.ly", + url: "https://your.domain.countly", test_mode: true }]) diff --git a/cypress/fixtures/referrer.html b/cypress/fixtures/referrer.html index 5b94d0a5..527414f1 100644 --- a/cypress/fixtures/referrer.html +++ b/cypress/fixtures/referrer.html @@ -4,7 +4,7 @@ */ -(function(root, factory) { - if (typeof define === "function" && define.amd) { - define([], function() { - return factory(root.Countly); +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Countly = global.Countly || {})); +})(this, (function(exports) { + 'use strict'; + + function _typeof(o) { + "@babel/helpers - typeof"; + + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) { + return typeof o; + } : function(o) { + return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; + }, _typeof(o); + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false }); + return Constructor; } - else if (typeof module === "object" && module.exports) { - module.exports = factory(root.Countly); + function _toPrimitive(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); } - else { - root.Countly = factory(root.Countly); + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return typeof key === "symbol" ? key : String(key); } -}(typeof window !== "undefined" ? window : this, function(Countly) { - var isBrowser = typeof window !== "undefined"; - /** @lends Countly */ - Countly = Countly || {}; + var isBrowser = typeof window !== "undefined"; + var Countly = globalThis.Countly || {}; /** * Array with list of available features that you can require consent for @@ -188,18 +226,15 @@ */ Countly.onload = Countly.onload || []; - var SDK_VERSION = "23.6.3"; + var SDK_VERSION = "23.12.0"; var SDK_NAME = "javascript_native_web"; // Using this on document.referrer would return an array with 15 elements in it. The 12th element (array[11]) would be the path we are looking for. Others would be things like password and such (use https://regex101.com/ to check more) var urlParseRE = /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/; var apmLibrariesNotLoaded = true; // used to prevent loading apm scripts multiple times. - /** - * @this Countly - * @param {Object} ob - Configuration object - */ - var CountlyClass = function(ob) { + var CountlyClass = /*#__PURE__*/_createClass(function CountlyClass(ob) { + _classCallCheck(this, CountlyClass); var self = this; var global = !Countly.i; var sessionStarted = false; @@ -385,7 +420,7 @@ } } - if ((this.passed_data && this.passed_data.app_key && this.passed_data.app_key === this.app_key) || (this.passed_data && !this.passed_data.app_key && global)) { + if (this.passed_data && this.passed_data.app_key && this.passed_data.app_key === this.app_key || this.passed_data && !this.passed_data.app_key && global) { if (this.passed_data.token && this.passed_data.purpose) { if (this.passed_data.token !== getValueFromStorage("cly_old_token")) { setToken(this.passed_data.token); @@ -574,7 +609,7 @@ } // flag that indicates that the offline mode was enabled at the end of the previous app session - var tempIdModeWasEnabled = (getValueFromStorage("cly_id") === "[CLY]_temp_id"); + var tempIdModeWasEnabled = getValueFromStorage("cly_id") === "[CLY]_temp_id"; var developerSetDeviceId = getConfig("device_id", ob, undefined); if (typeof developerSetDeviceId === "number") { // device ID should always be string developerSetDeviceId = developerSetDeviceId.toString(); @@ -970,7 +1005,7 @@ }; var consentTimer; - var updateConsent = function() { + var updateConsent = function updateConsent() { if (consentTimer) { // delay syncing consents clearTimeout(consentTimer); @@ -1065,7 +1100,7 @@ } lastBeat = getTimestamp(); sessionStarted = true; - autoExtend = !(noHeartBeat); + autoExtend = !noHeartBeat; var expire = getValueFromStorage("cly_session"); log(logLevelEnums.VERBOSE, "begin_session, Session state, forced: [" + force + "], useSessionCookie: [" + useSessionCookie + "], seconds to expire: [" + (expire - lastBeat) + "], expired: [" + (parseInt(expire) <= getTimestamp()) + "] "); if (force || !useSessionCookie || !expire || parseInt(expire) <= getTimestamp()) { @@ -1078,7 +1113,7 @@ req.metrics = JSON.stringify(getMetrics()); toRequestQueue(req); } - setValueInStorage("cly_session", getTimestamp() + (sessionCookieTimeout * 60)); + setValueInStorage("cly_session", getTimestamp() + sessionCookieTimeout * 60); } } else { @@ -1346,8 +1381,8 @@ add_cly_events({ key: internalEventKeyEnums.ORIENTATION, segmentation: { - mode: orientation || getOrientation(), - }, + mode: orientation || getOrientation() + } }); } }; @@ -1429,7 +1464,7 @@ * - addToSet, creates an array property, if property does not exist, and adds unique value to array, only if it does not yet exist in array ************************* */ var customData = {}; - var change_custom_property = function(key, value, mod) { + var change_custom_property = function change_custom_property(key, value, mod) { if (self.check_consent(featureEnums.USERS)) { if (!customData[key]) { customData[key] = {}; @@ -1467,7 +1502,7 @@ * @param {string} key - name of the property to attach to user * @param {string|number} value - value to store under provided property * */ - set: function(key, value) { + set: function set(key, value) { log(logLevelEnums.INFO, "[userData] set, Setting user's custom property value: [" + value + "] under the key: [" + key + "]"); // truncate user's custom property value to internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData set", log); @@ -1479,7 +1514,7 @@ * @memberof Countly.userData * @param {string} key - name of the property to delete * */ - unset: function(key) { + unset: function unset(key) { log(logLevelEnums.INFO, "[userData] unset, Resetting user's custom property with key: [" + key + "] "); customData[key] = ""; }, @@ -1489,7 +1524,7 @@ * @param {string} key - name of the property to attach to user * @param {string|number} value - value to store under provided property * */ - set_once: function(key, value) { + set_once: function set_once(key, value) { log(logLevelEnums.INFO, "[userData] set_once, Setting user's unique custom property value: [" + value + "] under the key: [" + key + "] "); // truncate user's custom property value to internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData set_once", log); @@ -1501,7 +1536,7 @@ * @memberof Countly.userData * @param {string} key - name of the property to attach to user * */ - increment: function(key) { + increment: function increment(key) { log(logLevelEnums.INFO, "[userData] increment, Increasing user's custom property value under the key: [" + key + "] by one"); // truncate property name wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData increment", log); @@ -1513,7 +1548,7 @@ * @param {string} key - name of the property to attach to user * @param {number} value - value by which to increment server value * */ - increment_by: function(key, value) { + increment_by: function increment_by(key, value) { log(logLevelEnums.INFO, "[userData] increment_by, Increasing user's custom property value under the key: [" + key + "] by: [" + value + "]"); // truncate property name and value wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData increment_by", log); @@ -1526,7 +1561,7 @@ * @param {string} key - name of the property to attach to user * @param {number} value - value by which to multiply server value * */ - multiply: function(key, value) { + multiply: function multiply(key, value) { log(logLevelEnums.INFO, "[userData] multiply, Multiplying user's custom property value under the key: [" + key + "] by: [" + value + "]"); // truncate key value pair wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData multiply", log); @@ -1539,7 +1574,7 @@ * @param {string} key - name of the property to attach to user * @param {number} value - value which to compare to server's value and store maximal value of both provided * */ - max: function(key, value) { + max: function max(key, value) { log(logLevelEnums.INFO, "[userData] max, Saving user's maximum custom property value compared to the value: [" + value + "] under the key: [" + key + "]"); // truncate key value pair wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData max", log); @@ -1552,7 +1587,7 @@ * @param {string} key - name of the property to attach to user * @param {number} value - value which to compare to server's value and store minimal value of both provided * */ - min: function(key, value) { + min: function min(key, value) { log(logLevelEnums.INFO, "[userData] min, Saving user's minimum custom property value compared to the value: [" + value + "] under the key: [" + key + "]"); // truncate key value pair wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData min", log); @@ -1565,7 +1600,7 @@ * @param {string} key - name of the property to attach to user * @param {string|number} value - value which to add to array * */ - push: function(key, value) { + push: function push(key, value) { log(logLevelEnums.INFO, "[userData] push, Pushing a value: [" + value + "] under the key: [" + key + "] to user's custom property array"); // truncate key value pair wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData push", log); @@ -1578,7 +1613,7 @@ * @param {string} key - name of the property to attach to user * @param {string|number} value - value which to add to array * */ - push_unique: function(key, value) { + push_unique: function push_unique(key, value) { log(logLevelEnums.INFO, "[userData] push_unique, Pushing a unique value: [" + value + "] under the key: [" + key + "] to user's custom property array"); // truncate key value pair wrt internal limits key = truncateSingleValue(key, self.maxKeyLength, "userData push_unique", log); @@ -1591,7 +1626,7 @@ * @param {string} key - name of the property * @param {string|number} value - value which to remove from array * */ - pull: function(key, value) { + pull: function pull(key, value) { log(logLevelEnums.INFO, "[userData] pull, Removing the value: [" + value + "] under the key: [" + key + "] from user's custom property array"); change_custom_property(key, value, "$pull"); }, @@ -1599,7 +1634,7 @@ * Save changes made to user's custom properties object and send them to server * @memberof Countly.userData * */ - save: function() { + save: function save() { log(logLevelEnums.INFO, "[userData] save, Saving changes to user's custom property"); if (self.check_consent(featureEnums.USERS)) { sendEventsForced(); // flush events to event queue to prevent a drill issue @@ -1638,7 +1673,9 @@ var date = new Date(); e.hour = date.getHours(); e.dow = date.getDay(); - toRequestQueue({ apm: JSON.stringify(e) }); + toRequestQueue({ + apm: JSON.stringify(e) + }); log(logLevelEnums.INFO, "report_trace, Successfully adding APM trace: ", e); } }; @@ -1667,7 +1704,7 @@ } // fallback if no error object is present for older browsers, we create it instead else { - col = col || (window.event && window.event.errorCharacter); + col = col || window.event && window.event.errorCharacter; var error = ""; if (typeof msg !== "undefined") { error += msg + "\n"; @@ -1682,7 +1719,6 @@ error += ":" + col; } error += "\n"; - try { var stack = []; // deprecated, must be changed @@ -1693,8 +1729,7 @@ f = f.caller; } error += stack.join("\n"); - } - catch (ex) { + } catch (ex) { log(logLevelEnums.ERROR, "track_errors, Call stack generation experienced a problem: " + ex); } // false indicates fatal error (as in non_fatal:false) @@ -1783,7 +1818,6 @@ fetch_remote_config_explicit(keysFiltered, omitKeysFiltered, opt, null, callbackFiltered); return; } - log(logLevelEnums.WARNING, "fetch_remote_config, Fetching remote config, with legacy API"); fetch_remote_config_explicit(keysFiltered, omitKeysFiltered, null, "legacy", callbackFiltered); }; @@ -1839,25 +1873,24 @@ try { var configs = JSON.parse(responseText); if (request.keys || request.omit_keys) { - // we merge config + // we merge config for (var i in configs) { remoteConfigs[i] = configs[i]; } } else { - // we replace config + // we replace config remoteConfigs = configs; } setValueInStorage("cly_remote_configs", remoteConfigs); - } - catch (ex) { + } catch (ex) { log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Had an issue while parsing the response: " + ex); } if (providedCall) { log(logLevelEnums.INFO, "fetch_remote_config_explicit, Callback function is provided"); providedCall(err, remoteConfigs); } - // JSON array can pass + // JSON array can pass }, true); } else { @@ -1892,8 +1925,7 @@ try { var resp = JSON.parse(responseText); log(logLevelEnums.DEBUG, "enrollUserToAb, Parsed the response's result: [" + resp.result + "]"); - } - catch (ex) { + } catch (ex) { log(logLevelEnums.ERROR, "enrollUserToAb, Had an issue while parsing the response: " + ex); } // JSON array can pass @@ -2013,7 +2045,6 @@ } inactivityCounter = 0; } - add_event_listener(window, "mousemove", resetInactivity); add_event_listener(window, "click", resetInactivity); add_event_listener(window, "keydown", resetInactivity); @@ -2069,7 +2100,6 @@ log(logLevelEnums.ERROR, "track_pageview, View name returned as null. Page view will be ignored."); return; } - if (ignoreList && ignoreList.length) { for (var i = 0; i < ignoreList.length; i++) { try { @@ -2078,8 +2108,7 @@ log(logLevelEnums.INFO, "track_pageview, Ignoring the page: " + page); return; } - } - catch (ex) { + } catch (ex) { log(logLevelEnums.ERROR, "track_pageview, Problem with finding ignore list item: " + ignoreList[i] + ", error: " + ex); } } @@ -2097,7 +2126,6 @@ if (this.track_domains) { segments.domain = window.location.hostname; } - if (useSessionCookie) { if (!sessionStarted) { // tracking view was called before tracking session, so we check expiration ourselves @@ -2143,7 +2171,6 @@ if (viewSegments) { viewSegments = truncateObject(viewSegments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "track_pageview", log); - for (var key in viewSegments) { if (typeof segments[key] === "undefined") { segments[key] = viewSegments[key]; @@ -2249,7 +2276,6 @@ parent = parent || window; isScrollRegistryOpen = true; trackingScrolls = true; - add_event_listener(parent, "scroll", processScroll); add_event_listener(parent, "beforeunload", processScrollView); }; @@ -2275,7 +2301,6 @@ function processClick(event) { // get element which was clicked var elem = get_closest_element(get_event_target(event), "a"); - if (elem) { // cross browser click coordinates get_page_coord(event); @@ -2309,7 +2334,7 @@ log(logLevelEnums.WARNING, "track_forms, window object is not available. Not tracking forms."); return; } - log(logLevelEnums.INFO, "track_forms, Starting to track form submissions. DOM object provided:[" + (!!parent) + "] Tracking hidden inputs :[" + (!!trackHidden) + "]"); + log(logLevelEnums.INFO, "track_forms, Starting to track form submissions. DOM object provided:[" + !!parent + "] Tracking hidden inputs :[" + !!trackHidden + "]"); parent = parent || document; /** * Get name of the input @@ -2403,7 +2428,7 @@ log(logLevelEnums.WARNING, "collect_from_forms, window object is not available. Not collecting from forms."); return; } - log(logLevelEnums.INFO, "collect_from_forms, Starting to collect possible user data. DOM object provided:[" + (!!parent) + "] Submitting custom user property:[" + (!!useCustom) + "]"); + log(logLevelEnums.INFO, "collect_from_forms, Starting to collect possible user data. DOM object provided:[" + !!parent + "] Submitting custom user property:[" + !!useCustom + "]"); parent = parent || document; /** * Process form data @@ -2475,43 +2500,31 @@ } } // check for email - else if ((input.type && input.type.toLowerCase() === "email") - || (input.name && input.name.toLowerCase().indexOf("email") !== -1) - || (input.id && input.id.toLowerCase().indexOf("email") !== -1) - || (input.id && labelData[input.id] && labelData[input.id].toLowerCase().indexOf("email") !== -1) - || (/[^@\s]+@[^@\s]+\.[^@\s]+/).test(value)) { + else if (input.type && input.type.toLowerCase() === "email" || input.name && input.name.toLowerCase().indexOf("email") !== -1 || input.id && input.id.toLowerCase().indexOf("email") !== -1 || input.id && labelData[input.id] && labelData[input.id].toLowerCase().indexOf("email") !== -1 || /[^@\s]+@[^@\s]+\.[^@\s]+/.test(value)) { if (!userdata.email) { userdata.email = value; } hasUserInfo = true; } - else if ((input.name && input.name.toLowerCase().indexOf("username") !== -1) - || (input.id && input.id.toLowerCase().indexOf("username") !== -1) - || (input.id && labelData[input.id] && labelData[input.id].toLowerCase().indexOf("username") !== -1)) { + else if (input.name && input.name.toLowerCase().indexOf("username") !== -1 || input.id && input.id.toLowerCase().indexOf("username") !== -1 || input.id && labelData[input.id] && labelData[input.id].toLowerCase().indexOf("username") !== -1) { if (!userdata.username) { userdata.username = value; } hasUserInfo = true; } - else if ((input.name && (input.name.toLowerCase().indexOf("tel") !== -1 || input.name.toLowerCase().indexOf("phone") !== -1 || input.name.toLowerCase().indexOf("number") !== -1)) - || (input.id && (input.id.toLowerCase().indexOf("tel") !== -1 || input.id.toLowerCase().indexOf("phone") !== -1 || input.id.toLowerCase().indexOf("number") !== -1)) - || (input.id && labelData[input.id] && (labelData[input.id].toLowerCase().indexOf("tel") !== -1 || labelData[input.id].toLowerCase().indexOf("phone") !== -1 || labelData[input.id].toLowerCase().indexOf("number") !== -1))) { + else if (input.name && (input.name.toLowerCase().indexOf("tel") !== -1 || input.name.toLowerCase().indexOf("phone") !== -1 || input.name.toLowerCase().indexOf("number") !== -1) || input.id && (input.id.toLowerCase().indexOf("tel") !== -1 || input.id.toLowerCase().indexOf("phone") !== -1 || input.id.toLowerCase().indexOf("number") !== -1) || input.id && labelData[input.id] && (labelData[input.id].toLowerCase().indexOf("tel") !== -1 || labelData[input.id].toLowerCase().indexOf("phone") !== -1 || labelData[input.id].toLowerCase().indexOf("number") !== -1)) { if (!userdata.phone) { userdata.phone = value; } hasUserInfo = true; } - else if ((input.name && (input.name.toLowerCase().indexOf("org") !== -1 || input.name.toLowerCase().indexOf("company") !== -1)) - || (input.id && (input.id.toLowerCase().indexOf("org") !== -1 || input.id.toLowerCase().indexOf("company") !== -1)) - || (input.id && labelData[input.id] && (labelData[input.id].toLowerCase().indexOf("org") !== -1 || labelData[input.id].toLowerCase().indexOf("company") !== -1))) { + else if (input.name && (input.name.toLowerCase().indexOf("org") !== -1 || input.name.toLowerCase().indexOf("company") !== -1) || input.id && (input.id.toLowerCase().indexOf("org") !== -1 || input.id.toLowerCase().indexOf("company") !== -1) || input.id && labelData[input.id] && (labelData[input.id].toLowerCase().indexOf("org") !== -1 || labelData[input.id].toLowerCase().indexOf("company") !== -1)) { if (!userdata.organization) { userdata.organization = value; } hasUserInfo = true; } - else if ((input.name && input.name.toLowerCase().indexOf("name") !== -1) - || (input.id && input.id.toLowerCase().indexOf("name") !== -1) - || (input.id && labelData[input.id] && labelData[input.id].toLowerCase().indexOf("name") !== -1)) { + else if (input.name && input.name.toLowerCase().indexOf("name") !== -1 || input.id && input.id.toLowerCase().indexOf("name") !== -1 || input.id && labelData[input.id] && labelData[input.id].toLowerCase().indexOf("name") !== -1) { if (!userdata.name) { userdata.name = ""; } @@ -2527,7 +2540,9 @@ if (hasUserInfo) { log(logLevelEnums.INFO, "collect_from_forms, Gathered user data", userdata); if (useCustom) { - self.user_details({ custom: userdata }); + self.user_details({ + custom: userdata + }); } else { self.user_details(userdata); @@ -2723,7 +2738,6 @@ log(logLevelEnums.ERROR, "reportFeedbackWidgetManually, Feedback Widgets can not be reported in offline mode"); return; } - log(logLevelEnums.INFO, "reportFeedbackWidgetManually, Providing information about user with, provided result of the widget with ID: [ " + CountlyFeedbackWidget._id + " ] and type: [" + CountlyFeedbackWidget.type + "]"); // type specific checks to see if everything was provided @@ -2793,7 +2807,6 @@ app_version: this.metrics._app_version || this.app_version } }; - if (widgetResult === null) { event.segmentation.closed = 1; } @@ -2837,7 +2850,10 @@ log(logLevelEnums.ERROR, "presentRatingWidgetWithID, Cannot show ratingWidget popup in offline mode"); } else { - makeNetworkRequest("presentRatingWidgetWithID,", this.url + "/o/feedback/widget", { widget_id: id, av: self.app_version }, function(err, params, responseText) { + makeNetworkRequest("presentRatingWidgetWithID,", this.url + "/o/feedback/widget", { + widget_id: id, + av: self.app_version + }, function(err, params, responseText) { if (err) { // error has been logged by the request function return; @@ -2846,11 +2862,10 @@ // widget object var currentWidget = JSON.parse(responseText); processWidget(currentWidget, false); - } - catch (JSONParseError) { + } catch (JSONParseError) { log(logLevelEnums.ERROR, "presentRatingWidgetWithID, JSON parse failed: " + JSONParseError); } - // JSON array can pass + // JSON array can pass }, true); } }; @@ -2891,8 +2906,10 @@ while (stickers.length > 0) { stickers[0].remove(); } - - makeNetworkRequest("initializeRatingWidgets,", this.url + "/o/feedback/multiple-widgets-by-id", { widgets: JSON.stringify(enableWidgets), av: self.app_version }, function(err, params, responseText) { + makeNetworkRequest("initializeRatingWidgets,", this.url + "/o/feedback/multiple-widgets-by-id", { + widgets: JSON.stringify(enableWidgets), + av: self.app_version + }, function(err, params, responseText) { if (err) { // error has been logged by the request function return; @@ -2921,7 +2938,7 @@ var isWildcardMatched = pages[k].substr(0, pages[k].length - 1) === window.location.pathname.substr(0, pages[k].length - 1); var isFullPathMatched = pages[k] === window.location.pathname; var isContainAsterisk = pages[k].includes("*"); - if (((isContainAsterisk && isWildcardMatched) || isFullPathMatched) && !widgets[i].hide_sticker) { + if ((isContainAsterisk && isWildcardMatched || isFullPathMatched) && !widgets[i].hide_sticker) { processWidget(widgets[i], true); } } @@ -2929,11 +2946,10 @@ } } } - } - catch (JSONParseError) { + } catch (JSONParseError) { log(logLevelEnums.ERROR, "initializeRatingWidgets, JSON parse error: " + JSONParseError); } - // JSON array can pass + // JSON array can pass }, true); }; @@ -2976,7 +2992,6 @@ // get enable widgets by app_key // define xhr object var enableWidgets = params.popups || params.widgets; - if (enableWidgets.length > 0) { document.body.insertAdjacentHTML("beforeend", "
"); this.initializeRatingWidgets(enableWidgets); @@ -2992,19 +3007,17 @@ * @param {Function} callback - Callback function with two parameters, 1st for returned list, 2nd for error * */ this.get_available_feedback_widgets = function(callback) { - log(logLevelEnums.INFO, "get_available_feedback_widgets, Getting the feedback list, callback function is provided:[" + (!!callback) + "]"); + log(logLevelEnums.INFO, "get_available_feedback_widgets, Getting the feedback list, callback function is provided:[" + !!callback + "]"); if (!this.check_consent(featureEnums.FEEDBACK)) { if (callback) { callback(null, new Error("Consent for feedback not provided.")); } return; } - if (offlineMode) { log(logLevelEnums.ERROR, "get_available_feedback_widgets, Cannot enable feedback widgets in offline mode."); return; } - var url = this.url + readPath; var data = { method: featureEnums.FEEDBACK, @@ -3012,7 +3025,6 @@ app_key: this.app_key, av: self.app_version }; - makeNetworkRequest("get_available_feedback_widgets,", url, data, function(err, params, responseText) { if (err) { // error has been logged by the request function @@ -3021,21 +3033,19 @@ } return; } - try { var response = JSON.parse(responseText); var feedbacks = response.result || []; if (callback) { callback(feedbacks, null); } - } - catch (error) { + } catch (error) { log(logLevelEnums.ERROR, "get_available_feedback_widgets, Error while parsing feedback widgets list: " + error); if (callback) { callback(null, error); } } - // expected response is JSON object + // expected response is JSON object }, false); }; @@ -3049,19 +3059,17 @@ log(logLevelEnums.ERROR, "getFeedbackWidgetData, Expected the provided widget object to have a type but got: [" + JSON.stringify(CountlyFeedbackWidget) + "], aborting."); return; } - log(logLevelEnums.INFO, "getFeedbackWidgetData, Retrieving data for: [" + JSON.stringify(CountlyFeedbackWidget) + "], callback function is provided:[" + (!!callback) + "]"); + log(logLevelEnums.INFO, "getFeedbackWidgetData, Retrieving data for: [" + JSON.stringify(CountlyFeedbackWidget) + "], callback function is provided:[" + !!callback + "]"); if (!this.check_consent(featureEnums.FEEDBACK)) { if (callback) { callback(null, new Error("Consent for feedback not provided.")); } return; } - if (offlineMode) { log(logLevelEnums.ERROR, "getFeedbackWidgetData, Cannot enable feedback widgets in offline mode."); return; } - var url = this.url; var data = { widget_id: CountlyFeedbackWidget._id, @@ -3071,7 +3079,6 @@ platform: this.platform, app_version: this.app_version }; - if (CountlyFeedbackWidget.type === "nps") { url += "/o/surveys/nps/widget"; } @@ -3085,7 +3092,6 @@ log(logLevelEnums.ERROR, "getFeedbackWidgetData, Unknown type info: [" + CountlyFeedbackWidget.type + "]"); return; } - makeNetworkRequest("getFeedbackWidgetData,", url, data, responseCallback, true); /** @@ -3102,15 +3108,13 @@ } return; } - try { var response = JSON.parse(responseText); // return parsed response if (callback) { callback(response, null); } - } - catch (error) { + } catch (error) { log(logLevelEnums.ERROR, "getFeedbackWidgetData, Error while parsing feedback widgets list: " + error); if (callback) { callback(null, error); @@ -3133,28 +3137,20 @@ } // TODO: feedbackWidgetSegmentation implementation only assumes we want to send segmentation data. Change it if we add more data to the custom object. log(logLevelEnums.INFO, "present_feedback_widget, Presenting the feedback widget by appending to the element with ID: [ " + id + " ] and className: [ " + className + " ]"); - if (!this.check_consent(featureEnums.FEEDBACK)) { return; } - - if (!presentableFeedback - || (typeof presentableFeedback !== "object") - || Array.isArray(presentableFeedback) - ) { + if (!presentableFeedback || _typeof(presentableFeedback) !== "object" || Array.isArray(presentableFeedback)) { log(logLevelEnums.ERROR, "present_feedback_widget, Please provide at least one feedback widget object."); return; } - log(logLevelEnums.INFO, "present_feedback_widget, Adding segmentation to feedback widgets:[" + JSON.stringify(feedbackWidgetSegmentation) + "]"); - if (!feedbackWidgetSegmentation || typeof feedbackWidgetSegmentation !== "object" || Object.keys(feedbackWidgetSegmentation).length === 0) { + if (!feedbackWidgetSegmentation || _typeof(feedbackWidgetSegmentation) !== "object" || Object.keys(feedbackWidgetSegmentation).length === 0) { log(logLevelEnums.DEBUG, "present_feedback_widget, Segmentation is not an object or empty"); feedbackWidgetSegmentation = null; } - try { var url = this.url; - if (presentableFeedback.type === "nps") { log(logLevelEnums.DEBUG, "present_feedback_widget, Widget type: nps."); url += "/feedback/nps"; @@ -3171,7 +3167,6 @@ log(logLevelEnums.ERROR, "present_feedback_widget, Feedback widget only accepts nps, rating and survey types."); return; } - var passedOrigin = window.origin || window.location.origin; var feedbackWidgetFamily; @@ -3188,7 +3183,6 @@ loadCSS(this.url + "/surveys/stylesheets/countly-surveys.css"); feedbackWidgetFamily = "surveys"; } - url += "?widget_id=" + presentableFeedback._id; url += "&app_key=" + this.app_key; url += "&device_id=" + this.device_id; @@ -3205,12 +3199,10 @@ // Only web SDK passes origin and web url += "&origin=" + passedOrigin; url += "&widget_v=web"; - var iframe = document.createElement("iframe"); iframe.src = url; iframe.name = "countly-" + feedbackWidgetFamily + "-iframe"; iframe.id = "countly-" + feedbackWidgetFamily + "-iframe"; - var initiated = false; iframe.onload = function() { // This is used as a fallback for browsers where postMessage API doesn't work. @@ -3229,7 +3221,6 @@ initiated = true; log(logLevelEnums.DEBUG, "present_feedback_widget, Loaded iframe."); }; - var overlay = document.getElementById("csbg"); while (overlay) { // Remove any existing overlays @@ -3237,26 +3228,21 @@ overlay = document.getElementById("csbg"); log(logLevelEnums.DEBUG, "present_feedback_widget, Removing past overlay."); } - var wrapper = document.getElementsByClassName("countly-" + feedbackWidgetFamily + "-wrapper"); for (var i = 0; i < wrapper.length; i++) { // Remove any existing feedback wrappers wrapper[i].remove(); log(logLevelEnums.DEBUG, "present_feedback_widget, Removed a wrapper."); } - wrapper = document.createElement("div"); wrapper.className = "countly-" + feedbackWidgetFamily + "-wrapper"; wrapper.id = "countly-" + feedbackWidgetFamily + "-wrapper-" + presentableFeedback._id; - if (presentableFeedback.type === "survey") { // Set popup position wrapper.className = wrapper.className + " " + presentableFeedback.appearance.position; } - var element = document.body; var found = false; - if (id) { if (document.getElementById(id)) { element = document.getElementById(id); @@ -3266,7 +3252,6 @@ log(logLevelEnums.ERROR, "present_feedback_widget, Provided ID not found."); } } - if (!found) { // If the id element is not found check if a class was provided if (className) { @@ -3278,7 +3263,6 @@ } } } - element.insertAdjacentHTML("beforeend", "
"); element.appendChild(wrapper); if (presentableFeedback.type === "rating") { @@ -3295,107 +3279,93 @@ document.getElementById("countly-ratings-wrapper-" + presentableFeedback._id).style.display = "none"; }); } - wrapper.appendChild(iframe); log(logLevelEnums.DEBUG, "present_feedback_widget, Appended the iframe"); - add_event_listener(window, "message", function(e) { var data = {}; try { data = JSON.parse(e.data); log(logLevelEnums.DEBUG, "present_feedback_widget, Parsed response message " + data); - } - catch (ex) { + } catch (ex) { log(logLevelEnums.ERROR, "present_feedback_widget, Error while parsing message body " + ex); } - if (!data.close) { log(logLevelEnums.DEBUG, "present_feedback_widget, Closing signal not sent yet"); return; } - document.getElementById("countly-" + feedbackWidgetFamily + "-wrapper-" + presentableFeedback._id).style.display = "none"; document.getElementById("csbg").style.display = "none"; }); - if (presentableFeedback.type === "survey") { var surveyShown = false; // Set popup show policy switch (presentableFeedback.showPolicy) { - case "afterPageLoad": - if (document.readyState === "complete") { - if (!surveyShown) { - surveyShown = true; - showSurvey(presentableFeedback); - } - } - else { - add_event_listener(document, "readystatechange", function(e) { - if (e.target.readyState === "complete") { - if (!surveyShown) { - surveyShown = true; - showSurvey(presentableFeedback); - } - } - }); - } - - break; - - case "afterConstantDelay": - setTimeout(function() { - if (!surveyShown) { - surveyShown = true; - showSurvey(presentableFeedback); - } - }, 10000); - - break; - - case "onAbandon": - if (document.readyState === "complete") { - add_event_listener(document, "mouseleave", function() { + case "afterPageLoad": + if (document.readyState === "complete") { if (!surveyShown) { surveyShown = true; showSurvey(presentableFeedback); } - }); - } - else { - add_event_listener(document, "readystatechange", function(e) { - if (e.target.readyState === "complete") { - add_event_listener(document, "mouseleave", function() { + } + else { + add_event_listener(document, "readystatechange", function(e) { + if (e.target.readyState === "complete") { if (!surveyShown) { surveyShown = true; showSurvey(presentableFeedback); } - }); - } - }); - } - - break; - - case "onScrollHalfwayDown": - add_event_listener(window, "scroll", function() { - if (!surveyShown) { - var scrollY = Math.max(window.scrollY, document.body.scrollTop, document.documentElement.scrollTop); - var documentHeight = getDocHeight(); - if (scrollY >= (documentHeight / 2)) { + } + }); + } + break; + case "afterConstantDelay": + setTimeout(function() { + if (!surveyShown) { surveyShown = true; showSurvey(presentableFeedback); } + }, 10000); + break; + case "onAbandon": + if (document.readyState === "complete") { + add_event_listener(document, "mouseleave", function() { + if (!surveyShown) { + surveyShown = true; + showSurvey(presentableFeedback); + } + }); + } + else { + add_event_listener(document, "readystatechange", function(e) { + if (e.target.readyState === "complete") { + add_event_listener(document, "mouseleave", function() { + if (!surveyShown) { + surveyShown = true; + showSurvey(presentableFeedback); + } + }); + } + }); + } + break; + case "onScrollHalfwayDown": + add_event_listener(window, "scroll", function() { + if (!surveyShown) { + var scrollY = Math.max(window.scrollY, document.body.scrollTop, document.documentElement.scrollTop); + var documentHeight = getDocHeight(); + if (scrollY >= documentHeight / 2) { + surveyShown = true; + showSurvey(presentableFeedback); + } + } + }); + break; + default: + if (!surveyShown) { + surveyShown = true; + showSurvey(presentableFeedback); } - }); - - break; - - default: - if (!surveyShown) { - surveyShown = true; - showSurvey(presentableFeedback); - } } } else if (presentableFeedback.type === "nps") { @@ -3404,7 +3374,6 @@ } else if (presentableFeedback.type === "rating") { var ratingShown = false; - if (document.readyState === "complete") { if (!ratingShown) { ratingShown = true; @@ -3422,8 +3391,7 @@ }); } } - } - catch (e) { + } catch (e) { log(logLevelEnums.ERROR, "present_feedback_widget, Something went wrong while presenting the widget: " + e); } @@ -3447,8 +3415,8 @@ // create sticker wrapper element var sticker = document.createElement("div"); sticker.innerText = feedback.appearance.text; - sticker.style.color = ((feedback.appearance.text_color.length < 7) ? "#" + feedback.appearance.text_color : feedback.appearance.text_color); - sticker.style.backgroundColor = ((feedback.appearance.bg_color.length < 7) ? "#" + feedback.appearance.bg_color : feedback.appearance.bg_color); + sticker.style.color = feedback.appearance.text_color.length < 7 ? "#" + feedback.appearance.text_color : feedback.appearance.text_color; + sticker.style.backgroundColor = feedback.appearance.bg_color.length < 7 ? "#" + feedback.appearance.bg_color : feedback.appearance.bg_color; sticker.className = "countly-feedback-sticker " + feedback.appearance.position + "-" + feedback.appearance.size; sticker.id = "countly-feedback-sticker-" + feedback._id; document.body.appendChild(sticker); @@ -3481,7 +3449,7 @@ // crashSegments, if not null, was set while enabling error tracking segments = segments || crashSegments; var error = ""; - if (typeof err === "object") { + if (_typeof(err) === "object") { if (typeof err.stack !== "undefined") { error = err.stack; } @@ -3507,7 +3475,7 @@ error = err + ""; } // character limit check - if (error.length > (self.maxStackTraceLineLength * self.maxStackTraceLinesPerThread)) { + if (error.length > self.maxStackTraceLineLength * self.maxStackTraceLinesPerThread) { log(logLevelEnums.DEBUG, "record_error, Error stack is too long will be truncated"); // convert error into an array split from each newline var splittedError = error.split("\n"); @@ -3524,56 +3492,51 @@ // turn modified array back into error string error = splittedError.join("\n"); } - - nonfatal = !!(nonfatal); + nonfatal = !!nonfatal; var metrics = getMetrics(); - var obj = { _resolution: metrics._resolution, _error: error, _app_version: metrics._app_version, _run: getTimestamp() - startTime }; - + var obj = { + _resolution: metrics._resolution, + _error: error, + _app_version: metrics._app_version, + _run: getTimestamp() - startTime + }; obj._not_os_specific = true; obj._javascript = true; - var battery = navigator.battery || navigator.webkitBattery || navigator.mozBattery || navigator.msBattery; if (battery) { obj._bat = Math.floor(battery.level * 100); } - if (typeof navigator.onLine !== "undefined") { - obj._online = !!(navigator.onLine); + obj._online = !!navigator.onLine; } - if (isBrowser) { - obj._background = !(document.hasFocus()); + obj._background = !document.hasFocus(); } - if (crashLogs.length > 0) { obj._logs = crashLogs.join("\n"); } crashLogs = []; - obj._nonfatal = nonfatal; - obj._view = this.getViewName(); - if (typeof segments !== "undefined") { // truncate custom crash segment's key value pairs segments = truncateObject(segments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "record_error", log); obj._custom = segments; } - try { var canvas = document.createElement("canvas"); var gl = canvas.getContext("experimental-webgl"); obj._opengl = gl.getParameter(gl.VERSION); - } - catch (ex) { + } catch (ex) { log(logLevelEnums.ERROR, "Could not get the experimental-webgl context: " + ex); } // send userAgent string with the crash object incase it gets removed by a gateway var req = {}; req.crash = JSON.stringify(obj); - req.metrics = JSON.stringify({ _ua: metrics._ua }); - + req.metrics = JSON.stringify({ + _ua: metrics._ua + }); toRequestQueue(req); } }; @@ -3596,7 +3559,9 @@ function sendEventsForced() { if (eventQueue.length > 0) { log(logLevelEnums.DEBUG, "Flushing events"); - toRequestQueue({ events: JSON.stringify(eventQueue) }); + toRequestQueue({ + events: JSON.stringify(eventQueue) + }); eventQueue = []; setValueInStorage("cly_event", eventQueue); } @@ -3663,8 +3628,8 @@ stickerText.innerText = currentWidget.trigger_button_text; // create sticker wrapper element var sticker = document.createElement("div"); - sticker.style.color = ((currentWidget.trigger_font_color.length < 7) ? "#" + currentWidget.trigger_font_color : currentWidget.trigger_font_color); - sticker.style.backgroundColor = ((currentWidget.trigger_bg_color.length < 7) ? "#" + currentWidget.trigger_bg_color : currentWidget.trigger_bg_color); + sticker.style.color = currentWidget.trigger_font_color.length < 7 ? "#" + currentWidget.trigger_font_color : currentWidget.trigger_font_color; + sticker.style.backgroundColor = currentWidget.trigger_bg_color.length < 7 ? "#" + currentWidget.trigger_bg_color : currentWidget.trigger_bg_color; sticker.className = "countly-feedback-sticker " + currentWidget.trigger_position + "-" + currentWidget.trigger_size; sticker.id = "countly-feedback-sticker-" + currentWidget._id; svgIcon.appendChild(svgPath); @@ -3673,7 +3638,7 @@ document.body.appendChild(sticker); var smileySvg = document.getElementById("smileyPathInStickerSvg"); if (smileySvg) { - smileySvg.style.fill = ((currentWidget.trigger_font_color.length < 7) ? "#" + currentWidget.trigger_font_color : currentWidget.trigger_font_color); + smileySvg.style.fill = currentWidget.trigger_font_color.length < 7 ? "#" + currentWidget.trigger_font_color : currentWidget.trigger_font_color; } add_event_listener(document.getElementById("countly-feedback-sticker-" + currentWidget._id), "click", function() { document.getElementById("countly-iframe-wrapper-" + currentWidget._id).style.display = "block"; @@ -3684,8 +3649,7 @@ document.getElementById("countly-iframe-wrapper-" + currentWidget._id).style.display = "block"; document.getElementById("cfbg").style.display = "block"; } - } - catch (e) { + } catch (e) { log(logLevelEnums.ERROR, "Somethings went wrong while element injecting process: " + e); } } @@ -3720,7 +3684,7 @@ if (self.check_consent(featureEnums.VIEWS)) { add_cly_events({ key: internalEventKeyEnums.VIEW, - dur: (trackTime) ? getTimestamp() - lastViewTime : lastViewStoredDuration, + dur: trackTime ? getTimestamp() - lastViewTime : lastViewStoredDuration, segmentation: segments }, currentViewId); lastView = null; @@ -3748,7 +3712,7 @@ sessionStarted = false; self.begin_session(!autoExtend); } - setValueInStorage("cly_session", getTimestamp() + (sessionCookieTimeout * 60)); + setValueInStorage("cly_session", getTimestamp() + sessionCookieTimeout * 60); } } @@ -3763,28 +3727,29 @@ request.sdk_version = SDK_VERSION; request.t = deviceIdType; request.av = self.app_version; - var ua = getUA(); - if (!request.metrics) { // if metrics not provided pass useragent with this event - request.metrics = JSON.stringify({ _ua: ua }); + if (!request.metrics) { + // if metrics not provided pass useragent with this event + request.metrics = JSON.stringify({ + _ua: ua + }); } - else { // if metrics provided + else { + // if metrics provided var currentMetrics = JSON.parse(request.metrics); - if (!currentMetrics._ua) { // check if ua is present and if not add that + if (!currentMetrics._ua) { + // check if ua is present and if not add that currentMetrics._ua = ua; request.metrics = JSON.stringify(currentMetrics); } } - if (self.check_consent(featureEnums.LOCATION)) { if (self.country_code) { request.country_code = self.country_code; } - if (self.city) { request.city = self.city; } - if (self.ip_address !== null) { request.ip_address = self.ip_address; } @@ -3792,9 +3757,7 @@ else { request.location = ""; } - request.timestamp = getMsTimestamp(); - var date = new Date(); request.hour = date.getHours(); request.dow = date.getDay(); @@ -3810,18 +3773,14 @@ log(logLevelEnums.WARNING, "User is opt_out will ignore the request: " + request); return; } - if (!self.app_key || !self.device_id) { log(logLevelEnums.ERROR, "app_key or device_id is missing ", self.app_key, self.device_id); return; } - prepareRequest(request); - if (requestQueue.length > queueSize) { requestQueue.shift(); } - requestQueue.push(request); setValueInStorage("cly_queue", requestQueue, true); } @@ -3840,7 +3799,6 @@ log(logLevelEnums.WARNING, "User opt_out, no heartbeat"); return; } - hasPulse = true; var i = 0; // process queue @@ -3897,12 +3855,16 @@ // process event queue if (eventQueue.length > 0 && !self.test_mode_eq) { if (eventQueue.length <= maxEventBatch) { - toRequestQueue({ events: JSON.stringify(eventQueue) }); + toRequestQueue({ + events: JSON.stringify(eventQueue) + }); eventQueue = []; } else { var events = eventQueue.splice(0, maxEventBatch); - toRequestQueue({ events: JSON.stringify(events) }); + toRequestQueue({ + events: JSON.stringify(events) + }); } setValueInStorage("cly_event", eventQueue); } @@ -3921,16 +3883,15 @@ failTimeout = getTimestamp() + failTimeoutAmount; } else { - // remove first item from queue + // remove first item from queue requestQueue.shift(); } setValueInStorage("cly_queue", requestQueue, true); readyToProcess = true; - // expected response is only JSON object + // expected response is only JSON object }, false); } } - setTimeout(heartBeat, beatInterval); } @@ -3981,8 +3942,8 @@ // getting resolution if (isBrowser && screen.width) { - var width = (screen.width) ? parseInt(screen.width) : 0; - var height = (screen.height) ? parseInt(screen.height) : 0; + var width = screen.width ? parseInt(screen.width) : 0; + var height = screen.height ? parseInt(screen.height) : 0; if (width !== 0 && height !== 0) { var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); if (iOS && window.devicePixelRatio) { @@ -4013,11 +3974,9 @@ if (typeof locale !== "undefined") { metrics._locale = metrics._locale || locale; } - if (isReferrerUsable()) { metrics._store = metrics._store || document.referrer; } - log(logLevelEnums.DEBUG, "Got metrics", metrics); return metrics; } @@ -4071,7 +4030,6 @@ } } } - return isReferrerLegit; } @@ -4084,7 +4042,7 @@ function log(level, message) { if (self.debug && typeof console !== "undefined") { // parse the arguments into a string if it is an object - if (arguments[2] && typeof arguments[2] === "object") { + if (arguments[2] && _typeof(arguments[2]) === "object") { arguments[2] = JSON.stringify(arguments[2]); } // append app_key to the start of the message if it is not the first instance (for multi instancing) @@ -4213,8 +4171,7 @@ else { xhr.send(data); } - } - catch (e) { + } catch (e) { // fallback log(logLevelEnums.ERROR, functionName + " Something went wrong while making an XML HTTP request: " + e); if (typeof callback === "function") { @@ -4235,15 +4192,15 @@ function sendFetchRequest(functionName, url, params, callback, useBroadResponseValidator) { useBroadResponseValidator = useBroadResponseValidator || false; var response; - try { log(logLevelEnums.DEBUG, "Sending Fetch request"); // Prepare request options var method = "GET"; - var headers = { "Content-type": "application/x-www-form-urlencoded" }; + var headers = { + "Content-type": "application/x-www-form-urlencoded" + }; var body = null; - params = params || {}; if (self.force_post || prepareParams(params).length >= 2000) { method = "POST"; @@ -4262,7 +4219,7 @@ fetch(url, { method: method, headers: headers, - body: body, + body: body }).then(function(res) { response = res; return response.text(); @@ -4275,7 +4232,6 @@ else { isResponseValidated = isResponseValid(response.status, data); } - if (isResponseValidated) { if (typeof callback === "function") { callback(false, params, data); @@ -4290,14 +4246,13 @@ callback(true, params, response.status, data); } } - }).catch(function(error) { + })["catch"](function(error) { log(logLevelEnums.ERROR, functionName + " Failed Fetch request: " + error); if (typeof callback === "function") { callback(true, params); } }); - } - catch (e) { + } catch (e) { // fallback log(logLevelEnums.ERROR, functionName + " Something went wrong with the Fetch request attempt: " + e); if (typeof callback === "function") { @@ -4331,10 +4286,8 @@ log(logLevelEnums.ERROR, "Http response is not JSON Object"); return false; } - - return !!(parsedResponse.result); - } - catch (e) { + return !!parsedResponse.result; + } catch (e) { log(logLevelEnums.ERROR, "Http response is not JSON: " + e); return false; } @@ -4360,15 +4313,14 @@ try { var parsedResponse = JSON.parse(str); // check if parsed response is a JSON object or JSON array, if not it is not valid - if ((Object.prototype.toString.call(parsedResponse) !== "[object Object]") && (!Array.isArray(parsedResponse))) { + if (Object.prototype.toString.call(parsedResponse) !== "[object Object]" && !Array.isArray(parsedResponse)) { log(logLevelEnums.ERROR, "Http response is not JSON Object nor JSON Array"); return false; } // request should be accepted even if does not have result field return true; - } - catch (e) { + } catch (e) { log(logLevelEnums.ERROR, "Http response is not JSON: " + e); return false; } @@ -4400,9 +4352,7 @@ isScrollRegistryOpen = false; var height = getDocHeight(); var width = getDocWidth(); - var viewportHeight = getViewportHeight(); - if (self.check_consent(featureEnums.SCROLLS)) { var segments = { type: "scroll", @@ -4411,7 +4361,7 @@ height: height, view: self.getViewUrl() }; - // truncate new segment + // truncate new segment segments = truncateObject(segments, self.maxKeyLength, self.maxValueSize, self.maxSegmentationValues, "processScrollView", log); if (self.track_domains) { segments.domain = window.location.hostname; @@ -4504,7 +4454,7 @@ */ function createCookie(cookieKey, cookieVal, exp) { var date = new Date(); - date.setTime(date.getTime() + (exp * 24 * 60 * 60 * 1000)); + date.setTime(date.getTime() + exp * 24 * 60 * 60 * 1000); // TODO: If we offer the developer the ability to manipulate the expiration date in the future, this part must be reworked var expires = "; expires=" + date.toGMTString(); document.cookie = cookieKey + "=" + cookieVal + expires + "; path=/"; @@ -4520,7 +4470,7 @@ */ function getValueFromStorage(key, useLocalStorage, useRawKey) { // check if we should use storage at all. If in worker context but no storage is available, return early - if (self.storage === "none" || (typeof self.storage !== "object" && !isBrowser)) { + if (self.storage === "none" || _typeof(self.storage) !== "object" && !isBrowser) { log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: [" + key + "] won't be retrieved"); return; } @@ -4532,10 +4482,9 @@ key = stripTrailingSlash(self.namespace) + "/" + key; } } - var data; // use dev provided storage if available - if (typeof self.storage === "object" && typeof self.storage.getItem === "function") { + if (_typeof(self.storage) === "object" && typeof self.storage.getItem === "function") { data = self.storage.getItem(key); return key.endsWith("cly_id") ? data : self.deserialize(data); } @@ -4546,10 +4495,12 @@ } // Get value - if (useLocalStorage) { // Native support + if (useLocalStorage) { + // Native support data = localStorage.getItem(key); } - else if (self.storage !== "localstorage") { // Use cookie + else if (self.storage !== "localstorage") { + // Use cookie data = readCookie(key); } @@ -4557,7 +4508,6 @@ if (key.endsWith("cly_id")) { return data; } - return self.deserialize(data); } @@ -4571,7 +4521,7 @@ */ function setValueInStorage(key, value, useLocalStorage, useRawKey) { // check if we should use storage options at all - if (self.storage === "none" || (typeof self.storage !== "object" && !isBrowser)) { + if (self.storage === "none" || _typeof(self.storage) !== "object" && !isBrowser) { log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: " + key + " won't be stored"); return; } @@ -4583,10 +4533,9 @@ key = stripTrailingSlash(self.namespace) + "/" + key; } } - if (typeof value !== "undefined" && value !== null) { // use dev provided storage if available - if (typeof self.storage === "object" && typeof self.storage.setItem === "function") { + if (_typeof(self.storage) === "object" && typeof self.storage.setItem === "function") { self.storage.setItem(key, value); return; } @@ -4595,13 +4544,14 @@ if (useLocalStorage === undefined) { useLocalStorage = lsSupport; } - value = self.serialize(value); // Set the store - if (useLocalStorage) { // Native support + if (useLocalStorage) { + // Native support localStorage.setItem(key, value); } - else if (self.storage !== "localstorage") { // Use Cookie + else if (self.storage !== "localstorage") { + // Use Cookie createCookie(key, value, 30); } } @@ -4616,7 +4566,7 @@ */ function removeValueFromStorage(key, useLocalStorage, useRawKey) { // check if we should use storage options at all - if (self.storage === "none" || (typeof self.storage !== "object" && !isBrowser)) { + if (self.storage === "none" || _typeof(self.storage) !== "object" && !isBrowser) { log(logLevelEnums.DEBUG, "Storage is disabled. Value with key: " + key + " won't be removed"); return; } @@ -4630,7 +4580,7 @@ } // use dev provided storage if available - if (typeof self.storage === "object" && typeof self.storage.removeItem === "function") { + if (_typeof(self.storage) === "object" && typeof self.storage.removeItem === "function") { self.storage.removeItem(key); return; } @@ -4639,11 +4589,12 @@ if (useLocalStorage === undefined) { useLocalStorage = lsSupport; } - - if (useLocalStorage) { // Native support + if (useLocalStorage) { + // Native support localStorage.removeItem(key); } - else if (self.storage !== "localstorage") { // Use cookie + else if (self.storage !== "localstorage") { + // Use cookie createCookie(key, "", -1); } } @@ -4696,28 +4647,27 @@ log(logLevelEnums.DEBUG, "onStorageChange, Applying storage changes for key:", key); log(logLevelEnums.DEBUG, "onStorageChange, Applying storage changes for value:", newValue); switch (key) { - // queue of requests - case "cly_queue": - requestQueue = self.deserialize(newValue || "[]"); - break; + // queue of requests + case "cly_queue": + requestQueue = self.deserialize(newValue || "[]"); + break; // queue of events - case "cly_event": - eventQueue = self.deserialize(newValue || "[]"); - break; - case "cly_remote_configs": - remoteConfigs = self.deserialize(newValue || "{}"); - break; - case "cly_ignore": - self.ignore_visitor = self.deserialize(newValue); - break; - case "cly_id": - self.device_id = newValue; - break; - case "cly_id_type": - deviceIdType = self.deserialize(newValue); - break; - default: - // do nothing + case "cly_event": + eventQueue = self.deserialize(newValue || "[]"); + break; + case "cly_remote_configs": + remoteConfigs = self.deserialize(newValue || "{}"); + break; + case "cly_ignore": + self.ignore_visitor = self.deserialize(newValue); + break; + case "cly_id": + self.device_id = newValue; + break; + case "cly_id_type": + deviceIdType = self.deserialize(newValue); + break; + // do nothing } }; @@ -4784,7 +4734,7 @@ * Clear queued data * @memberof Countly._internals */ - clearQueue: function() { + clearQueue: function clearQueue() { requestQueue = []; setValueInStorage("cly_queue", []); eventQueue = []; @@ -4794,7 +4744,7 @@ * For testing pusposes only * @returns {Object} - returns the local queues */ - getLocalQueues: function() { + getLocalQueues: function getLocalQueues() { return { eventQ: eventQueue, requestQ: requestQueue @@ -4876,7 +4826,9 @@ // prepare request var request = { hc: JSON.stringify(hc), - metrics: JSON.stringify({ _app_version: self.app_version }) + metrics: JSON.stringify({ + _app_version: self.app_version + }) }; // add common request params prepareRequest(request); @@ -4892,12 +4844,8 @@ // initialize Countly Class this.initialize(); - }; + }); - /** - * Countly class - exposing so plugins can extend its prototype - * @param {Object} ob - Configuration object - */ Countly.CountlyClass = CountlyClass; /** @@ -4977,7 +4925,7 @@ } var appKey = conf.app_key || Countly.app_key; if (!Countly.i || !Countly.i[appKey]) { - var inst = new Countly.CountlyClass(conf); + var inst = new CountlyClass(conf); if (!Countly.i) { Countly.i = {}; for (var key in inst) { @@ -5132,7 +5080,6 @@ // Append boomerang script to the head document.getElementsByTagName("head")[0].appendChild(boomerangScript); document.getElementsByTagName("head")[0].appendChild(countlyBoomerangScript); - var boomLoaded = false; var countlyBoomLoaded = false; boomerangScript.onload = function() { @@ -5141,14 +5088,13 @@ countlyBoomerangScript.onload = function() { countlyBoomLoaded = true; }; - var timeoutCounter = 0; var intervalDuration = 50; var timeoutLimit = 1500; // TODO: Configurable? Mb with Countly.apmScriptLoadTimeout? // init Countly only after boomerang is loaded var intervalID = setInterval(function() { timeoutCounter += intervalDuration; - if ((boomLoaded && countlyBoomLoaded) || (timeoutCounter >= timeoutLimit)) { + if (boomLoaded && countlyBoomLoaded || timeoutCounter >= timeoutLimit) { if (Countly.debug) { var message = "BoomerangJS loaded:[" + boomLoaded + "], countly_boomerang loaded:[" + countlyBoomLoaded + "]."; if (boomLoaded && countlyBoomLoaded) { @@ -5196,8 +5142,7 @@ // timestamp in milliseconds var timestamp = Date.now().toString(); - - return (id + timestamp); + return id + timestamp; } /** @@ -5223,7 +5168,7 @@ var regex = new RegExp(pattern, "g"); return str.replace(regex, function(c) { var r = (d + Math.random() * 16) % 16 | 0; - return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16); + return (c === "x" ? r : r & 0x3 | 0x8).toString(16); }); } @@ -5235,7 +5180,6 @@ function getTimestamp() { return Math.floor(new Date().getTime() / 1000); } - var lastMsTs = 0; /** * Get unique timestamp in milliseconds @@ -5421,7 +5365,7 @@ * @param {String} nodeName - tag/node name * @returns {HTMLElement} closest parent element */ - var get_closest_element = function(el, nodeName) { + function get_closest_element(el, nodeName) { nodeName = nodeName.toUpperCase(); while (el) { if (el.nodeName.toUpperCase() === nodeName) { @@ -5429,7 +5373,7 @@ } el = el.parentElement; } - }; + } /** * Listen to specific browser event @@ -5438,11 +5382,12 @@ * @param {String} type - event name or action * @param {Function} listener - callback when event is fired */ - var add_event_listener = function(element, type, listener) { + function add_event_listener(element, type, listener) { if (!isBrowser) { return; } - if (element === null || typeof element === "undefined") { // element can be null so lets check it first + if (element === null || typeof element === "undefined") { + // element can be null so lets check it first if (checkIfLoggingIsOn()) { // eslint-disable-next-line no-console console.warn("[WARNING] [Countly] add_event_listener, Can't bind [" + type + "] event to nonexisting element"); @@ -5456,7 +5401,7 @@ else { element.attachEvent("on" + type, listener); } - }; + } /** * Get element that fired event @@ -5464,7 +5409,7 @@ * @param {Event} event - event that was filed * @returns {HTMLElement} HTML element that caused event to fire */ - var get_event_target = function(event) { + function get_event_target(event) { if (!event) { return window.event.srcElement; } @@ -5472,7 +5417,7 @@ return event.target; } return event.srcElement; - }; + } /** * Returns raw user agent string @@ -5484,7 +5429,6 @@ if (uaOverride) { return uaOverride; } - var ua_raw = navigator.userAgent; // check if userAgentData is supported and userAgent is not available, use it if (!ua_raw) { @@ -5494,7 +5438,7 @@ return e.brand + ":" + e.version; }).join(); // add mobile info - ua_raw += (navigator.userAgentData.mobile ? " mobi " : " "); + ua_raw += navigator.userAgentData.mobile ? " mobi " : " "; // add platform info ua_raw += navigator.userAgentData.platform; } @@ -5564,9 +5508,7 @@ */ function get_page_coord(e) { // checking if pageY and pageX is already available - if (typeof e.pageY === "undefined" - && typeof e.clientX === "number" - && document.documentElement) { + if (typeof e.pageY === "undefined" && typeof e.clientX === "number" && document.documentElement) { // if not, then add scrolling positions e.pageX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; e.pageY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; @@ -5582,11 +5524,7 @@ */ function getDocHeight() { var D = document; - return Math.max( - Math.max(D.body.scrollHeight, D.documentElement.scrollHeight), - Math.max(D.body.offsetHeight, D.documentElement.offsetHeight), - Math.max(D.body.clientHeight, D.documentElement.clientHeight) - ); + return Math.max(Math.max(D.body.scrollHeight, D.documentElement.scrollHeight), Math.max(D.body.offsetHeight, D.documentElement.offsetHeight), Math.max(D.body.clientHeight, D.documentElement.clientHeight)); } /** @@ -5596,11 +5534,7 @@ */ function getDocWidth() { var D = document; - return Math.max( - Math.max(D.body.scrollWidth, D.documentElement.scrollWidth), - Math.max(D.body.offsetWidth, D.documentElement.offsetWidth), - Math.max(D.body.clientWidth, D.documentElement.clientWidth) - ); + return Math.max(Math.max(D.body.scrollWidth, D.documentElement.scrollWidth), Math.max(D.body.offsetWidth, D.documentElement.offsetWidth), Math.max(D.body.clientWidth, D.documentElement.clientWidth)); } /** @@ -5610,11 +5544,7 @@ */ function getViewportHeight() { var D = document; - return Math.min( - Math.min(D.body.clientHeight, D.documentElement.clientHeight), - Math.min(D.body.offsetHeight, D.documentElement.offsetHeight), - window.innerHeight - ); + return Math.min(Math.min(D.body.clientHeight, D.documentElement.clientHeight), Math.min(D.body.offsetHeight, D.documentElement.offsetHeight), window.innerHeight); } /** @@ -5629,7 +5559,7 @@ * Monitor parallel storage changes like other opened tabs */ if (isBrowser) { - window.addEventListener("storage", function(e) { + window.addEventListener("storage", function (e) { var parts = (e.key + "").split("/"); var key = parts.pop(); var appKey = parts.pop(); @@ -5653,7 +5583,7 @@ var loaded; fileRef.setAttribute(attr, type); fileRef.setAttribute(src, data); - var callbackFunction = function() { + var callbackFunction = function callbackFunction() { if (!loaded) { callback(); } @@ -5696,9 +5626,7 @@ } var loader = document.getElementById("cly-loader"); if (!loader) { - var css = "#cly-loader {height: 4px; width: 100%; position: absolute; z-index: 99999; overflow: hidden; background-color: #fff; top:0px; left:0px;}" - + "#cly-loader:before{display: block; position: absolute; content: ''; left: -200px; width: 200px; height: 4px; background-color: #2EB52B; animation: cly-loading 2s linear infinite;}" - + "@keyframes cly-loading { from {left: -200px; width: 30%;} 50% {width: 30%;} 70% {width: 70%;} 80% { left: 50%;} 95% {left: 120%;} to {left: 100%;}}"; + var css = "#cly-loader {height: 4px; width: 100%; position: absolute; z-index: 99999; overflow: hidden; background-color: #fff; top:0px; left:0px;}" + "#cly-loader:before{display: block; position: absolute; content: ''; left: -200px; width: 200px; height: 4px; background-color: #2EB52B; animation: cly-loading 2s linear infinite;}" + "@keyframes cly-loading { from {left: -200px; width: 30%;} 50% {width: 30%;} 70% {width: 70%;} 80% { left: 50%;} 95% {left: 120%;} to {left: 100%;}}"; var head = document.head || document.getElementsByTagName("head")[0]; var style = document.createElement("style"); style.type = "text/css"; @@ -5722,8 +5650,7 @@ } try { document.body.appendChild(loader); - } - catch (e) { + } catch (e) { if (checkIfLoggingIsOn()) { // eslint-disable-next-line no-console console.error("[ERROR] [Countly] showLoader, Body is not loaded for loader to append: " + e); @@ -5770,7 +5697,7 @@ * */ Countly.serialize = function(value) { // Convert object values to JSON - if (typeof value === "object") { + if (_typeof(value) === "object") { value = JSON.stringify(value); } return value; @@ -5782,20 +5709,19 @@ * @return {varies} deserialized value * */ Countly.deserialize = function(data) { - if (data === "") { // we expect string or null only. Empty sting would throw an error. + if (data === "") { + // we expect string or null only. Empty sting would throw an error. return data; } // Try to parse JSON... try { data = JSON.parse(data); - } - catch (e) { + } catch (e) { if (checkIfLoggingIsOn()) { // eslint-disable-next-line no-console console.warn("[WARNING] [Countly] deserialize, Could not parse the file:[" + data + "], error: " + e); } } - return data; }; @@ -5841,5 +5767,10 @@ SDK_GENERATED: DeviceIdTypeInternalEnums.SDK_GENERATED, TEMPORARY_ID: DeviceIdTypeInternalEnums.TEMPORARY_ID }; - return Countly; -})); + + + exports.default = Countly; + + Object.defineProperty(exports, '__esModule', { value: true }); + +})); \ No newline at end of file diff --git a/lib/countly.min.js b/lib/countly.min.js index 659a0ddb..48604067 100644 --- a/lib/countly.min.js +++ b/lib/countly.min.js @@ -1,151 +1,157 @@ -(function(n,ta){"function"===typeof define&&define.amd?define([],function(){return ta(n.Countly)}):"object"===typeof module&&module.exports?module.exports=ta(n.Countly):n.Countly=ta(n.Countly)})("undefined"!==typeof window?window:this,function(n){function ta(h){var p=document.createElement("script"),u=document.createElement("script");p.async=!0;u.async=!0;p.src=n.customSourceBoomerang||ob.BOOMERANG_SRC;u.src=n.customSourceCountlyBoomerang||ob.CLY_BOOMERANG_SRC;document.getElementsByTagName("head")[0].appendChild(p); -document.getElementsByTagName("head")[0].appendChild(u);var A=!1,B=!1;p.onload=function(){A=!0};u.onload=function(){B=!0};var L=0,T=setInterval(function(){L+=50;if(A&&B||1500<=L){if(n.debug){var R="BoomerangJS loaded:["+A+"], countly_boomerang loaded:["+B+"].";A&&B?console.log("[DEBUG] "+R):console.warn("[WARNING] "+R+" Initializing without APM.")}n.init(h);clearInterval(T)}},50)}function pb(h){var p=[];if("undefined"!==typeof h.options)for(var u=0;u=h?Ia++:Ia=h;return Ia}function r(h,p,u){if(p&&Object.keys(p).length){if("undefined"!== -typeof p[h])return p[h]}else if("undefined"!==typeof n[h])return n[h];return u}function bb(h,p,u){for(var A in n.i)n.i[A].tracking_crashes&&n.i[A].recordError(h,p,u)}function rb(h){var p=[],u;for(u in h)p.push(u+"="+encodeURIComponent(h[u]));return p.join("&")}function oa(h){return"string"===typeof h&&"/"===h.substring(h.length-1)?h.substring(0,h.length-1):h}function ua(h,p){for(var u={},A,B=0,L=p.length;BA){var R={},va=0,Z;for(Z in h)vap&&(B=h.substring(0,p),A(d.DEBUG,u+", Key: [ "+h+" ] is longer than accepted length. It will be truncated."));return B}function pa(h){if(h)return h;h=navigator.userAgent;!h&&navigator.userAgentData&&(h=navigator.userAgentData.brands.map(function(p){return p.brand+ -":"+p.version}).join(),h+=navigator.userAgentData.mobile?" mobi ":" ",h+=navigator.userAgentData.platform);return h}function sb(h){if(!h){if(navigator.userAgentData.mobile)return"phone";h=pa()}h=h.toLowerCase();var p="desktop",u=/(mobi|ipod|phone|blackberry|opera mini|fennec|minimo|symbian|psp|nintendo ds|archos|skyfire|puffin|blazer|bolt|gobrowser|iris|maemo|semc|teashark|uzard)/;/(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(h)? -p="tablet":u.test(h)&&(p="phone");return p}function tb(h){return/(CountlySiteBot|nuhk|Googlebot|GoogleSecurityScanner|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver|bingbot|Google Web Preview|Mediapartners-Google|AdsBot-Google|Baiduspider|Ezooms|YahooSeeker|AltaVista|AVSearch|Mercator|Scooter|InfoSeek|Ultraseek|Lycos|Wget|YandexBot|Yandex|YaDirectFetcher|SiteBot|Exabot|AhrefsBot|MJ12bot|TurnitinBot|magpie-crawler|Nutch Crawler|CMS Crawler|rogerbot|Domnutch|ssearch_bot|XoviBot|netseer|digincore|fr-crawler|wesee|AliasIO|contxbot|PingdomBot|BingPreview|HeadlessChrome)/.test(h|| -pa())}function cb(h){"undefined"===typeof h.pageY&&"number"===typeof h.clientX&&document.documentElement&&(h.pageX=h.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,h.pageY=h.clientY+document.body.scrollTop+document.documentElement.scrollTop);return h}function Ja(){var h=document;return Math.max(Math.max(h.body.scrollHeight,h.documentElement.scrollHeight),Math.max(h.body.offsetHeight,h.documentElement.offsetHeight),Math.max(h.body.clientHeight,h.documentElement.clientHeight))} -function db(){var h=document;return Math.max(Math.max(h.body.scrollWidth,h.documentElement.scrollWidth),Math.max(h.body.offsetWidth,h.documentElement.offsetWidth),Math.max(h.body.clientWidth,h.documentElement.clientWidth))}function ub(){var h=document;return Math.min(Math.min(h.body.clientHeight,h.documentElement.clientHeight),Math.min(h.body.offsetHeight,h.documentElement.offsetHeight),window.innerHeight)}function vb(h,p,u,A,B,L){h=document.createElement(h);var T;h.setAttribute(p,u);h.setAttribute(A, -B);p=function(){T||L();T=!0};L&&(h.onreadystatechange=p,h.onload=p);document.getElementsByTagName("head")[0].appendChild(h)}function wb(h,p){vb("script","type","text/javascript","src",h,p)}function Ka(h,p){vb("link","rel","stylesheet","href",h,p)}function xb(){var h=document.getElementById("cly-loader");if(!h){var p=document.head||document.getElementsByTagName("head")[0],u=document.createElement("style");u.type="text/css";u.styleSheet?u.styleSheet.cssText="#cly-loader {height: 4px; width: 100%; position: absolute; z-index: 99999; overflow: hidden; background-color: #fff; top:0px; left:0px;}#cly-loader:before{display: block; position: absolute; content: ''; left: -200px; width: 200px; height: 4px; background-color: #2EB52B; animation: cly-loading 2s linear infinite;}@keyframes cly-loading { from {left: -200px; width: 30%;} 50% {width: 30%;} 70% {width: 70%;} 80% { left: 50%;} 95% {left: 120%;} to {left: 100%;}}": -u.appendChild(document.createTextNode("#cly-loader {height: 4px; width: 100%; position: absolute; z-index: 99999; overflow: hidden; background-color: #fff; top:0px; left:0px;}#cly-loader:before{display: block; position: absolute; content: ''; left: -200px; width: 200px; height: 4px; background-color: #2EB52B; animation: cly-loading 2s linear infinite;}@keyframes cly-loading { from {left: -200px; width: 30%;} 50% {width: 30%;} 70% {width: 70%;} 80% { left: 50%;} 95% {left: 120%;} to {left: 100%;}}")); -p.appendChild(u);h=document.createElement("div");h.setAttribute("id","cly-loader");document.body.onload=function(){if(n.showLoaderProtection)wa()&&console.warn("[WARNING] [Countly] showloader, Loader is already on");else try{document.body.appendChild(h)}catch(A){wa()&&console.error("[ERROR] [Countly] showLoader, Body is not loaded for loader to append: "+A)}}}h.style.display="block"}function wa(){return n&&n.debug&&"undefined"!==typeof console?!0:!1}function yb(){n.showLoaderProtection=!0;var h=document.getElementById("cly-loader"); -h&&(h.style.display="none")}if("undefined"!==typeof window){n=n||{};n.features="sessions events views scrolls clicks forms crashes attribution users star-rating location apm feedback remote-config".split(" ");var I={NPS:"[CLY]_nps",SURVEY:"[CLY]_survey",STAR_RATING:"[CLY]_star_rating",VIEW:"[CLY]_view",ORIENTATION:"[CLY]_orientation",ACTION:"[CLY]_action"},Jb=Object.values(I),d={ERROR:"[ERROR] ",WARNING:"[WARNING] ",INFO:"[INFO] ",DEBUG:"[DEBUG] ",VERBOSE:"[VERBOSE] "},ob={BOOMERANG_SRC:"https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/plugin/boomerang/boomerang.min.js", -CLY_BOOMERANG_SRC:"https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/plugin/boomerang/countly_boomerang.js"},P=Object.freeze({errorCount:"cly_hc_error_count",warningCount:"cly_hc_warning_count",statusCode:"cly_hc_status_code",errorMessage:"cly_hc_error_message"});n.q=n.q||[];n.onload=n.onload||[];var zb=/^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?::([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?::([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,Ab=!0;n.CountlyClass= -function(h){function p(a,c){if(f.ignore_visitor)b(d.ERROR,"Adding event failed. Possible bot or user opt out");else if(a.key){a.count||(a.count=1);Jb.includes(a.key)||(a.key=x(a.key,f.maxKeyLength,"add_cly_event",b));a.segmentation=Y(a.segmentation,f.maxKeyLength,f.maxValueSize,f.maxSegmentationValues,"add_cly_event",b);a=ua(a,["key","count","sum","dur","segmentation"]);a.timestamp=ab();var e=new Date;a.hour=e.getHours();a.dow=e.getDay();a.id=c||Za();a.key===I.VIEW?a.pvid=xa||"":a.cvid=fa||"";J.push(a); -v("cly_event",J);b(d.INFO,"With event ID: ["+a.id+"], successfully adding the last event:",a)}else b(d.ERROR,"Adding event failed. Event must have a key property")}function u(a,c,e,k,l){b(d.INFO,"fetch_remote_config_explicit, Fetching sequence initiated");var g={method:"rc",av:f.app_version};a&&(g.keys=JSON.stringify(a));c&&(g.omit_keys=JSON.stringify(c));var m;"legacy"===k&&(g.method="fetch_remote_config");0===e&&(g.oi=0);1===e&&(g.oi=1);"function"===typeof l&&(m=l);f.check_consent("sessions")&& -(g.metrics=JSON.stringify(La()));f.check_consent("remote-config")?(Z(g),aa("fetch_remote_config_explicit",f.url+Ma,g,function(q,t,K){if(q)b(d.ERROR,"fetch_remote_config_explicit, An error occurred: "+q);else{try{var N=JSON.parse(K);if(g.keys||g.omit_keys)for(var ka in N)O[ka]=N[ka];else O=N;v("cly_remote_configs",O)}catch(ya){b(d.ERROR,"fetch_remote_config_explicit, Had an issue while parsing the response: "+ya)}m&&(b(d.INFO,"fetch_remote_config_explicit, Callback function is provided"),m(q,O))}}, -!0)):(b(d.ERROR,"fetch_remote_config_explicit, Remote config requires explicit consent"),m&&m(Error("Remote config requires explicit consent"),O))}function A(){f.ignore_prefetch&&"undefined"!==typeof document.visibilityState&&"prerender"===document.visibilityState&&(f.ignore_visitor=!0);f.ignore_bots&&tb()&&(f.ignore_visitor=!0)}function B(){0a.trigger_font_color.length?"#"+a.trigger_font_color:a.trigger_font_color;t.style.backgroundColor=7>a.trigger_bg_color.length?"#"+a.trigger_bg_color:a.trigger_bg_color;t.className="countly-feedback-sticker "+a.trigger_position+"-"+a.trigger_size;t.id="countly-feedback-sticker-"+a._id;g.appendChild(m);t.appendChild(g);t.appendChild(q);document.body.appendChild(t);var K=document.getElementById("smileyPathInStickerSvg"); -K&&(K.style.fill=7>a.trigger_font_color.length?"#"+a.trigger_font_color:a.trigger_font_color);y(document.getElementById("countly-feedback-sticker-"+a._id),"click",function(){document.getElementById("countly-iframe-wrapper-"+a._id).style.display="block";document.getElementById("cfbg").style.display="block"})}else document.getElementById("countly-iframe-wrapper-"+a._id).style.display="block",document.getElementById("cfbg").style.display="block"}catch(N){b(d.ERROR,"Somethings went wrong while element injecting process: "+ -N)}}function T(){var a;if("undefined"!==typeof f.onload&&0Na&&F.shift(),F.push(a),v("cly_queue",F,!0)):b(d.ERROR,"app_key or device_id is missing ",f.app_key,f.device_id)}function Oa(){T();if(f.ignore_visitor)Pa=!1,b(d.WARNING,"User opt_out, no heartbeat");else{Pa=!0;var a=0;if(Qa&&"undefined"!==typeof n.q&&0Ra&&(f.session_duration(a-ia),ia=a,0eb&&(Sa=!1,a=F[0],a.rr=F.length,b(d.DEBUG,"Processing request",a),v("cly_queue",F,!0),f.test_mode||aa("send_request_queue",f.url+fb,a,function(m,q){b(d.DEBUG,"Request Finished",q,m);m?(eb=E()+Ta,b(d.ERROR,"Request error: ",m)):F.shift();v("cly_queue",F,!0);Sa=!0},!1));setTimeout(Oa,Ua)}}function gb(){var a=w("cly_id");return a?(C=w("cly_id_type"),a):$a()}function Bb(){return f.metrics._ua||pa()}function La(){var a= -JSON.parse(JSON.stringify(f.metrics||{}));a._app_version=a._app_version||f.app_version;a._ua=a._ua||pa();if(screen.width){var c=screen.width?parseInt(screen.width):0,e=screen.height?parseInt(screen.height):0;if(0!==c&&0!==e){if(navigator.platform&&/iPad|iPhone|iPod/.test(navigator.platform)&&window.devicePixelRatio)c=Math.round(c*window.devicePixelRatio),e=Math.round(e*window.devicePixelRatio);else if(90===Math.abs(window.orientation)){var k=c;c=e;e=k}a._resolution=a._resolution||""+c+"x"+e}}window.devicePixelRatio&& -(a._density=a._density||window.devicePixelRatio);c=navigator.language||navigator.browserLanguage||navigator.systemLanguage||navigator.userLanguage;"undefined"!==typeof c&&(a._locale=a._locale||c);hb()&&(a._store=a._store||document.referrer);b(d.DEBUG,"Got metrics",a);return a}function hb(a){a=a||document.referrer;var c=!1;if("undefined"===typeof a||0===a.length)b(d.DEBUG,"Invalid referrer:["+a+"], ignoring.");else{var e=zb.exec(a);if(e)if(e[11])if(e[11]===window.location.hostname)b(d.DEBUG,"Referrer is current host:["+ -a+"], ignoring.");else if(ba&&ba.length)for(c=!0,e=0;ea))return b(d.ERROR,"Http response status code is not within the expected range:["+a+"]"),!1;try{var e=JSON.parse(c);return"[object Object]"!==Object.prototype.toString.call(e)? -(b(d.ERROR,"Http response is not JSON Object"),!1):!!e.result}catch(k){return b(d.ERROR,"Http response is not JSON: "+k),!1}}function Cb(a,c){if(!(200<=a&&300>a))return b(d.ERROR,"Http response status code is not within the expected range: "+a),!1;try{var e=JSON.parse(c);return"[object Object]"===Object.prototype.toString.call(e)||Array.isArray(e)?!0:(b(d.ERROR,"Http response is not JSON Object nor JSON Array"),!1)}catch(k){return b(d.ERROR,"Http response is not JSON: "+k),!1}}function Eb(){Ea=Math.max(Ea, -window.scrollY,document.body.scrollTop,document.documentElement.scrollTop)}function ib(){if(Fa){Fa=!1;var a=Ja(),c=db(),e=ub();f.check_consent("scrolls")&&(a={type:"scroll",y:Ea+e,width:c,height:a,view:f.getViewUrl()},a=Y(a,f.maxKeyLength,f.maxValueSize,f.maxSegmentationValues,"processScrollView",b),f.track_domains&&(a.domain=window.location.hostname),p({key:I.ACTION,segmentation:a}))}}function Fb(a){v("cly_token",a)}function Gb(a,c,e){var k=new Date;k.setTime(k.getTime()+864E5*e);e="; expires="+ -k.toGMTString();document.cookie=a+"="+c+e+"; path=/"}function w(a,c,e){if("none"===f.storage)b(d.WARNING,"Storage is disabled. Value with key: "+a+" won't be retrieved");else{e||(a=f.app_key+"/"+a,f.namespace&&(a=oa(f.namespace)+"/"+a));void 0===c&&(c=ma);if(c)var k=localStorage.getItem(a);else if("localstorage"!==f.storage)a:{c=a+"=";e=document.cookie.split(";");k=0;for(var l=e.length;kwindow.innerHeight?"landscape":"portrait")}})};this.report_conversion=function(a,c){b(d.WARNING,"report_conversion, Deprecated function call! Use 'recordDirectAttribution' in place of this call. Call will be redirected now!");this.recordDirectAttribution(a,c)};this.recordDirectAttribution=function(a,c){b(d.INFO,"recordDirectAttribution, Recording the attribution for campaign ID: ["+a+"] and the user ID: ["+c+"]");this.check_consent("attribution")&&(a=a||w("cly_cmp_id")|| -"cly_organic",(c=c||w("cly_cmp_uid"))?G({campaign_id:a,campaign_user:c}):G({campaign_id:a}))};this.user_details=function(a){b(d.INFO,"user_details, Trying to add user details: ",a);this.check_consent("users")&&(B(),b(d.INFO,"user_details, flushed the event queue"),a.name=x(a.name,f.maxValueSize,"user_details",b),a.username=x(a.username,f.maxValueSize,"user_details",b),a.email=x(a.email,f.maxValueSize,"user_details",b),a.organization=x(a.organization,f.maxValueSize,"user_details",b),a.phone=x(a.phone, -f.maxValueSize,"user_details",b),a.picture=x(a.picture,4096,"user_details",b),a.gender=x(a.gender,f.maxValueSize,"user_details",b),a.byear=x(a.byear,f.maxValueSize,"user_details",b),a.custom=Y(a.custom,f.maxKeyLength,f.maxValueSize,f.maxSegmentationValues,"user_details",b),G({user_details:JSON.stringify(ua(a,"name username email organization phone picture gender byear custom".split(" ")))}))};var W={},ea=function(a,c,e){f.check_consent("users")&&(W[a]||(W[a]={}),"$push"===e||"$pull"===e||"$addToSet"=== -e?(W[a][e]||(W[a][e]=[]),W[a][e].push(c)):W[a][e]=c)};this.userData={set:function(a,c){b(d.INFO,"[userData] set, Setting user's custom property value: ["+c+"] under the key: ["+a+"]");a=x(a,f.maxKeyLength,"userData set",b);c=x(c,f.maxValueSize,"userData set",b);W[a]=c},unset:function(a){b(d.INFO,"[userData] unset, Resetting user's custom property with key: ["+a+"] ");W[a]=""},set_once:function(a,c){b(d.INFO,"[userData] set_once, Setting user's unique custom property value: ["+c+"] under the key: ["+ -a+"] ");a=x(a,f.maxKeyLength,"userData set_once",b);c=x(c,f.maxValueSize,"userData set_once",b);ea(a,c,"$setOnce")},increment:function(a){b(d.INFO,"[userData] increment, Increasing user's custom property value under the key: ["+a+"] by one");a=x(a,f.maxKeyLength,"userData increment",b);ea(a,1,"$inc")},increment_by:function(a,c){b(d.INFO,"[userData] increment_by, Increasing user's custom property value under the key: ["+a+"] by: ["+c+"]");a=x(a,f.maxKeyLength,"userData increment_by",b);c=x(c,f.maxValueSize, -"userData increment_by",b);ea(a,c,"$inc")},multiply:function(a,c){b(d.INFO,"[userData] multiply, Multiplying user's custom property value under the key: ["+a+"] by: ["+c+"]");a=x(a,f.maxKeyLength,"userData multiply",b);c=x(c,f.maxValueSize,"userData multiply",b);ea(a,c,"$mul")},max:function(a,c){b(d.INFO,"[userData] max, Saving user's maximum custom property value compared to the value: ["+c+"] under the key: ["+a+"]");a=x(a,f.maxKeyLength,"userData max",b);c=x(c,f.maxValueSize,"userData max",b); -ea(a,c,"$max")},min:function(a,c){b(d.INFO,"[userData] min, Saving user's minimum custom property value compared to the value: ["+c+"] under the key: ["+a+"]");a=x(a,f.maxKeyLength,"userData min",b);c=x(c,f.maxValueSize,"userData min",b);ea(a,c,"$min")},push:function(a,c){b(d.INFO,"[userData] push, Pushing a value: ["+c+"] under the key: ["+a+"] to user's custom property array");a=x(a,f.maxKeyLength,"userData push",b);c=x(c,f.maxValueSize,"userData push",b);ea(a,c,"$push")},push_unique:function(a, -c){b(d.INFO,"[userData] push_unique, Pushing a unique value: ["+c+"] under the key: ["+a+"] to user's custom property array");a=x(a,f.maxKeyLength,"userData push_unique",b);c=x(c,f.maxValueSize,"userData push_unique",b);ea(a,c,"$addToSet")},pull:function(a,c){b(d.INFO,"[userData] pull, Removing the value: ["+c+"] under the key: ["+a+"] from user's custom property array");ea(a,c,"$pull")},save:function(){b(d.INFO,"[userData] save, Saving changes to user's custom property");f.check_consent("users")&& -(B(),b(d.INFO,"user_details, flushed the event queue"),G({user_details:JSON.stringify({custom:W})}));W={}}};this.report_trace=function(a){b(d.INFO,"report_trace, Reporting performance trace");if(this.check_consent("apm")){for(var c="type name stz etz apm_metrics apm_attr".split(" "),e=0;e=f.maxBreadcrumbCount;)na.shift(),b(d.WARNING,"add_log, Reached maximum crashLogs size. Will erase the oldest one.");na.push(a)}};this.fetch_remote_config=function(a,c,e){var k=null,l=null,g=null;a&&(e||"function"!==typeof a?Array.isArray(a)&&(k=a):g=a); -c&&(e||"function"!==typeof c?Array.isArray(c)&&(l=c):g=c);g||"function"!==typeof e||(g=e);this.useExplicitRcApi?(b(d.INFO,"fetch_remote_config, Fetching remote config"),u(k,l,this.rcAutoOptinAb?1:0,null,g)):(b(d.WARNING,"fetch_remote_config, Fetching remote config, with legacy API"),u(k,l,null,"legacy",g))};this.enrollUserToAb=function(a){b(d.INFO,"enrollUserToAb, Providing AB test keys to opt in for");a&&Array.isArray(a)&&0!==a.length?(a={method:"ab",keys:JSON.stringify(a),av:f.app_version},Z(a), -aa("enrollUserToAb",this.url+Ma,a,function(c,e,k){if(c)b(d.ERROR,"enrollUserToAb, An error occurred: "+c);else try{var l=JSON.parse(k);b(d.DEBUG,"enrollUserToAb, Parsed the response's result: ["+l.result+"]")}catch(g){b(d.ERROR,"enrollUserToAb, Had an issue while parsing the response: "+g)}},!0)):b(d.ERROR,"enrollUserToAb, No keys provided")};this.get_remote_config=function(a){b(d.INFO,"get_remote_config, Getting remote config from storage");return"undefined"!==typeof a?O[a]:O};this.stop_time=function(){b(d.INFO, -"stop_time, Stopping tracking duration");la&&(la=!1,kb=E()-ia,Aa=E()-za)};this.start_time=function(){b(d.INFO,"start_time, Starting tracking duration");la||(la=!0,ia=E()-kb,za=E()-Aa,Aa=0,va())};this.track_sessions=function(){function a(){document[e]||!document.hasFocus()?f.stop_time():f.start_time()}function c(){Ha>=Ga&&f.start_time();Ha=0}b(d.INFO,"track_session, Starting tracking user session");this.begin_session();this.start_time();y(window,"beforeunload",function(){B();f.end_session()});var e= -"hidden";y(window,"focus",a);y(window,"blur",a);y(window,"pageshow",a);y(window,"pagehide",a);"onfocusin"in document&&(y(window,"focusin",a),y(window,"focusout",a));e in document?document.addEventListener("visibilitychange",a):"mozHidden"in document?(e="mozHidden",document.addEventListener("mozvisibilitychange",a)):"webkitHidden"in document?(e="webkitHidden",document.addEventListener("webkitvisibilitychange",a)):"msHidden"in document&&(e="msHidden",document.addEventListener("msvisibilitychange",a)); -y(window,"mousemove",c);y(window,"click",c);y(window,"keydown",c);y(window,"scroll",c);setInterval(function(){Ha++;Ha>=Ga&&f.stop_time()},6E4)};this.track_pageview=function(a,c,e){b(d.INFO,"track_pageview, Tracking page views");b(d.VERBOSE,"track_pageview, last view is:["+U+"], current view ID is:["+fa+"], previous view ID is:["+xa+"]");U&&lb&&(b(d.DEBUG,"track_pageview, Scroll registry triggered"),ib(),Fa=!0,Ea=0);R();xa=fa;fa=Za();(a=x(a,f.maxKeyLength,"track_pageview",b))&&Array.isArray(a)&&(c= -a,a=null);a||(a=this.getViewName());if(void 0===a||""===a)b(d.ERROR,"track_pageview, No page name to track (it is either undefined or empty string). No page view can be tracked.");else if(null===a)b(d.ERROR,"track_pageview, View name returned as null. Page view will be ignored.");else{if(c&&c.length)for(var k=0;k