@gumlet/insights-js-core 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.github/workflows/main.yml +87 -0
  2. package/.gitlab-ci.yml +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +30 -0
  5. package/bitbucket-pipelines.yml +35 -0
  6. package/docs/payload-documentation.md +72 -0
  7. package/html/bitmovin.html +82 -0
  8. package/html/dashjs.html +55 -0
  9. package/html/hlsjs.html +72 -0
  10. package/html/html5.html +59 -0
  11. package/html/shaka.html +102 -0
  12. package/html/videojs.html +67 -0
  13. package/index.html +73 -0
  14. package/jest.config.js +187 -0
  15. package/js/adapters/Bitmovin7Adapter.js +352 -0
  16. package/js/adapters/BitmovinAdapter.js +198 -0
  17. package/js/adapters/DashjsAdapter.js +140 -0
  18. package/js/adapters/HTML5Adapter.js +774 -0
  19. package/js/adapters/HlsjsAdapter.js +152 -0
  20. package/js/adapters/ShakaAdapter.js +81 -0
  21. package/js/adapters/VideoJsAdapter.js +455 -0
  22. package/js/analyticsStateMachines/Bitmovin7AnalyticsStateMachine.js +471 -0
  23. package/js/analyticsStateMachines/BitmovinAnalyticsStateMachine.js +299 -0
  24. package/js/analyticsStateMachines/HTML5AnalyticsStateMachine.js +443 -0
  25. package/js/analyticsStateMachines/VideoJsAnalyticsStateMachine.js +503 -0
  26. package/js/cast/CastClient.js +50 -0
  27. package/js/cast/CastReceiver.js +37 -0
  28. package/js/core/AdapterFactory.js +41 -0
  29. package/js/core/Analytics.js +1357 -0
  30. package/js/core/AnalyticsStateMachineFactory.js +36 -0
  31. package/js/core/GumletInsightsExport.js +75 -0
  32. package/js/enums/CDNProviders.js +11 -0
  33. package/js/enums/Events.js +32 -0
  34. package/js/enums/GumletEnum.js +19 -0
  35. package/js/enums/MIMETypes.js +30 -0
  36. package/js/enums/Players.js +11 -0
  37. package/js/enums/StreamTypes.js +15 -0
  38. package/js/utils/EventsCall.js +22 -0
  39. package/js/utils/HttpCall.js +57 -0
  40. package/js/utils/LicenseCall.js +18 -0
  41. package/js/utils/Logger.js +40 -0
  42. package/js/utils/PlayerDetector.js +75 -0
  43. package/js/utils/PlayerInitCall.js +22 -0
  44. package/js/utils/SessionCreationCall.js +22 -0
  45. package/js/utils/Settings.js +3 -0
  46. package/js/utils/Utils.js +195 -0
  47. package/package.json +62 -1
  48. package/precommit.bash +8 -0
  49. package/tests/stage1.test.js +50 -0
  50. package/webpack.config.debug.js +34 -0
  51. package/webpack.config.js +40 -0
  52. package/webpack.config.release.js +62 -0
  53. package/gumlet-insights.min.js +0 -2
  54. package/gumlet-insights.min.js.LICENSE.txt +0 -10
@@ -0,0 +1,36 @@
1
+ import PlayerDetector from '../utils/PlayerDetector';
2
+ import {BitmovinAnalyticsStateMachine} from '../analyticsStateMachines/BitmovinAnalyticsStateMachine';
3
+ import {Bitmovin7AnalyticsStateMachine} from '../analyticsStateMachines/Bitmovin7AnalyticsStateMachine';
4
+ import {VideojsAnalyticsStateMachine} from '../analyticsStateMachines/VideoJsAnalyticsStateMachine';
5
+ import {HTML5AnalyticsStateMachine} from '../analyticsStateMachines/HTML5AnalyticsStateMachine';
6
+
7
+ /**
8
+ * Stateless. Auto-maps given player instance to new state-machine instances.
9
+ * @class
10
+ */
11
+ class AnalyticsStateMachineFactory {
12
+ /**
13
+ * @param {object} player
14
+ * @param {AnalyticsStateMachineCallbacks} stateMachineCallbacks
15
+ * @param {AnalyticsStateMachineOptions} opts
16
+ */
17
+ static getAnalyticsStateMachine(player, stateMachineCallbacks, opts = {}) {
18
+ if (PlayerDetector.isBitmovinVersionPre7(player)) {
19
+ return new BitmovinAnalyticsStateMachine(stateMachineCallbacks, opts);
20
+ } else if (PlayerDetector.isBitmovinVersion7Plus(player)) {
21
+ return new Bitmovin7AnalyticsStateMachine(stateMachineCallbacks, opts);
22
+ } else if (PlayerDetector.isVideoJs(player)) {
23
+ return new VideojsAnalyticsStateMachine(stateMachineCallbacks, opts);
24
+ } else if (
25
+ PlayerDetector.isHlsjs(player) ||
26
+ PlayerDetector.isDashjs(player) ||
27
+ PlayerDetector.isShaka(player)) {
28
+ return new HTML5AnalyticsStateMachine(stateMachineCallbacks, opts);
29
+ } else {
30
+ // throw new Error('Could not detect player type');
31
+ return new HTML5AnalyticsStateMachine(stateMachineCallbacks, opts);
32
+ }
33
+ }
34
+ }
35
+
36
+ export default AnalyticsStateMachineFactory;
@@ -0,0 +1,75 @@
1
+ import Analytics from './Analytics';
2
+ import {Players} from '../enums/Players';
3
+ import CdnProviders from '../enums/CDNProviders';
4
+ import EVENTS from "../enums/Events";
5
+
6
+ let analytics;
7
+
8
+ const register = (player, opts = {}) => {
9
+ return analytics.register(player, opts);
10
+ };
11
+
12
+ const registerVideoJSPlayer = (player, opts = {}) => {
13
+ return analytics.registerVideoJSPlayer(player, opts);
14
+ };
15
+
16
+ const registerDashJSPlayer = (player, opts = {}) => {
17
+ return analytics.registerDashJSPlayer(player, opts);
18
+ };
19
+
20
+ const registerHLSJSPlayer = (player, opts = {}) => {
21
+ return analytics.registerHLSJSPlayer(player, opts);
22
+ };
23
+
24
+ const registerShakaPlayer = (player, opts = {}) => {
25
+ return analytics.registerShakaPlayer(player, opts);
26
+ };
27
+
28
+ const registerHTML5Player = (player, opts = {}) => {
29
+ return analytics.registerHTML5Player(player, opts);
30
+ };
31
+
32
+ const registerReactNativeVideoPlayer = (player, opts = {}) => {
33
+ return analytics.registerReactNativeVideoPlayer(player, opts);
34
+ };
35
+
36
+ const getCurrentImpressionId = () => {
37
+ return analytics.getCurrentImpressionId();
38
+ };
39
+
40
+ const getAnalyticsStateMachine = () => {
41
+ return analytics.analyticsStateMachine;
42
+ };
43
+
44
+ const analyticsWrapper = (config) => {
45
+ analytics = new Analytics(config);
46
+ return {
47
+ register : register,
48
+ registerVideoJSPlayer : registerVideoJSPlayer,
49
+ registerDashJSPlayer : registerDashJSPlayer,
50
+ registerHLSJSPlayer : registerHLSJSPlayer,
51
+ registerShakaPlayer : registerShakaPlayer,
52
+ registerHTML5Player : registerHTML5Player,
53
+ registerReactNativeVideoPlayer: registerReactNativeVideoPlayer,
54
+ getCurrentImpressionId : getCurrentImpressionId,
55
+ stateMachine : getAnalyticsStateMachine,
56
+ setCustomData : analytics.setCustomData,
57
+ setCustomDataOnce : analytics.setCustomDataOnce,
58
+ };
59
+ };
60
+
61
+ analyticsWrapper.Players = Players;
62
+ analyticsWrapper.CdnProviders = CdnProviders;
63
+
64
+ if (typeof window !== "undefined")
65
+ {
66
+ window.gumlet = window.gumlet || {};
67
+ window.gumlet.insights = analyticsWrapper;
68
+ window.gumletInsightsEvents = EVENTS;
69
+ window.gumletSupportedPlayers = Players;
70
+ }
71
+ else{
72
+
73
+ }
74
+
75
+ export default analyticsWrapper;
@@ -0,0 +1,11 @@
1
+ const CdnProviders = {
2
+ CLOUDFLARE: 'cloudflare',
3
+ AKAMAI: 'akamai',
4
+ FASTLY: 'fastly',
5
+ MAXCDN: 'maxcdn',
6
+ CLOUDFRONT: 'cloudfront',
7
+ CHINACACHE: 'chinacache',
8
+ BITGRAVITY: 'bitgravity'
9
+ };
10
+
11
+ export default CdnProviders;
@@ -0,0 +1,32 @@
1
+ const Events = {
2
+ READY : 'ready',
3
+ STARTUP : 'startup',
4
+ SOURCE_LOADED : 'sourceLoaded',
5
+ PLAY : 'play',
6
+ PAUSE : 'pause',
7
+ TIMECHANGED : 'timechanged',
8
+ SEEK : 'seek',
9
+ SEEKED : 'seeked',
10
+ START_CAST : 'startCasting',
11
+ END_CAST : 'endCasting',
12
+ START_BUFFERING : 'startBuffering',
13
+ END_BUFFERING : 'endBuffering',
14
+ AUDIO_CHANGE : 'audioChange',
15
+ VIDEO_CHANGE : 'videoChange',
16
+ START_FULLSCREEN : 'startFullscreen',
17
+ END_FULLSCREEN : 'endFullscreen',
18
+ START_AD : 'adStart',
19
+ END_AD : 'adEnd',
20
+ MUTE : 'mute',
21
+ UN_MUTE : 'unMute',
22
+ ERROR : 'playerError',
23
+ PLAYBACK_FINISHED: 'end',
24
+ SCREEN_RESIZE : 'resize',
25
+ UNLOAD : 'unload',
26
+ END : 'end',
27
+ METADATA_LOADED : 'metadataLoaded',
28
+ SOURCE_UNLOADED : 'sourceUnloaded',
29
+ PLAYBACK_PLAYING : 'playback_playing',
30
+ };
31
+
32
+ export default Events;
@@ -0,0 +1,19 @@
1
+ const GumletEventEnum = {
2
+ SETUP : 'event_setup',
3
+ PLAYER_READY : 'event_player_ready',
4
+ PLAYBACK_READY : 'event_playback_ready',
5
+ PLAYBACK_STARTED : 'event_playback_started',
6
+ PAUSE : 'event_pause',
7
+ PLAY : 'event_play',
8
+ PLAYING : 'event_playing',
9
+ PLAYBACK_UPDATE : 'event_playback_update',
10
+ END : 'event_ended',
11
+ MUTE : 'event_muted',
12
+ UNMUTE : 'event_unmute',
13
+ SEEKED : 'event_seeked',
14
+ START_REBUFFER : 'event_rebuffer_start',
15
+ END_REBUFFER : 'event_rebuffer_end',
16
+ ERROR : 'event_error',
17
+ };
18
+
19
+ export default GumletEventEnum;
@@ -0,0 +1,30 @@
1
+ const MP4 = 'video/mp4';
2
+ const WEBM = 'video/webm';
3
+ const HLS = 'application/x-mpegURL';
4
+ const DASH = 'application/dash+xml';
5
+
6
+ export const MIMETypes = {
7
+ MP4,
8
+ WEBM,
9
+ HLS,
10
+ DASH
11
+ };
12
+
13
+ export function getMIMETypeFromFileExtension(path) {
14
+
15
+ path = path.toLowerCase();
16
+
17
+ if (path.endsWith('.m3u8')) {
18
+ return HLS;
19
+ }
20
+ if (path.endsWith('.mp4') || path.endsWith('.m4v') || path.endsWith('.m4a')) {
21
+ return MP4;
22
+ }
23
+ if (path.endsWith('.webm')) {
24
+ return WEBM;
25
+ }
26
+ if (path.endsWith('.mpd')) {
27
+ return DASH;
28
+ }
29
+ return null;
30
+ }
@@ -0,0 +1,11 @@
1
+ export const Players = {
2
+ BITMOVIN : 'bitmovin',
3
+ JW : 'jw',
4
+ RADIANT : 'radiant',
5
+ VIDEOJS : 'videojs',
6
+ HLSJS : 'hlsjs',
7
+ SHAKA : 'shaka',
8
+ DASHJS : 'dashjs',
9
+ HTML : 'html5',
10
+ REACTNATIVEVIDEO : 'react-native-video'
11
+ };
@@ -0,0 +1,15 @@
1
+ import {MIMETypes} from './MIMETypes';
2
+
3
+ const { MP4, WEBM, HLS, DASH } = MIMETypes;
4
+
5
+ const mapping = {
6
+ [MP4]: 'mp4',
7
+ [WEBM]: 'webm',
8
+ [HLS]: 'hls',
9
+ [DASH]: 'dash'
10
+ };
11
+
12
+ export function getStreamTypeFromMIMEType(mimeType) {
13
+ return mapping[mimeType];
14
+ }
15
+
@@ -0,0 +1,22 @@
1
+ import HttpCall from './HttpCall';
2
+ import {ANALYTICS_BACKEND_BASE_URL} from './Settings';
3
+
4
+ class EventsCall extends HttpCall{
5
+ static analyticsServerUrl = ANALYTICS_BACKEND_BASE_URL;
6
+
7
+ sendRequest = function(sample, callback) {
8
+ sample.event_family = 'session_event';
9
+ this.get(EventsCall.analyticsServerUrl, sample, callback);
10
+ };
11
+
12
+ sendRequestSynchronous = function(sample, callback) {
13
+ sample.event_family = 'session_event';
14
+ this.get(EventsCall.analyticsServerUrl, sample, callback, false);
15
+ };
16
+
17
+ getAnalyticsServerUrl = function() {
18
+ return EventsCall.analyticsServerUrl;
19
+ }
20
+ }
21
+
22
+ export default EventsCall;
@@ -0,0 +1,57 @@
1
+ import Utils from '../utils/Utils';
2
+
3
+ class HttpCall {
4
+ get(url, body, callback, async = true) {
5
+ let xhttp;
6
+ let legacyMode = false;
7
+
8
+ if (window.XDomainRequest) {
9
+ legacyMode = true;
10
+ }
11
+
12
+ if (legacyMode) {
13
+ xhttp = new window.XDomainRequest();
14
+ } else {
15
+ xhttp = new XMLHttpRequest();
16
+ }
17
+
18
+ const responseCallback = function() {
19
+ if (xhttp.readyState == XMLHttpRequest.DONE) {
20
+ if (xhttp.responseText <= 0) {
21
+ return;
22
+ }
23
+
24
+ const sampleResponse = JSON.parse(xhttp.responseText);
25
+
26
+ callback(sampleResponse);
27
+ }
28
+ };
29
+
30
+ if (legacyMode) {
31
+ xhttp.onload = responseCallback;
32
+ } else {
33
+ xhttp.onreadystatechange = responseCallback;
34
+ }
35
+
36
+ // TODO: resolve to milliseconds
37
+ body['z'] = (new Date()).getTime()/1000;
38
+
39
+ const removeUnwantedValues = [undefined, null, false]
40
+
41
+ // Body cleanup
42
+ Object.keys(body).forEach(key => removeUnwantedValues.indexOf(body[key]) !== -1 && delete body[key])
43
+ // Remove NaN from payload
44
+ // Since NaN is the only JavaScript value that is treated as unequal to itself
45
+ Object.keys(body).forEach(key => body[key] !== body[key] && delete body[key])
46
+
47
+ // Create the queryString for URL
48
+ let queryString = Utils.jsonToQueryString(body);
49
+ url += queryString;
50
+
51
+ xhttp.open('GET', url, async);
52
+
53
+ xhttp.send(null);
54
+ }
55
+ }
56
+
57
+ export default HttpCall;
@@ -0,0 +1,18 @@
1
+ import HttpCall from './HttpCall';
2
+ import {ANALYTICS_BACKEND_BASE_URL} from './Settings';
3
+
4
+ class LicenseCall extends HttpCall {
5
+ static licenseServerUrl = ANALYTICS_BACKEND_BASE_URL + '/licensing';
6
+
7
+ sendRequest = function(key, domain, version, callback) {
8
+ const licensingRequest = {
9
+ key: key,
10
+ domain: domain,
11
+ analyticsVersion: version
12
+ };
13
+
14
+ this.get(LicenseCall.licenseServerUrl, licensingRequest, callback);
15
+ };
16
+ }
17
+
18
+ export default LicenseCall;
@@ -0,0 +1,40 @@
1
+ class Logger {
2
+ constructor(showLogs = false) {
3
+ this.showLogs = showLogs;
4
+ }
5
+
6
+ setLogging(logging) {
7
+ this.showLogs = logging;
8
+ }
9
+
10
+ isLogging() {
11
+ return this.showLogs;
12
+ }
13
+
14
+ log = function(msg) {
15
+ if (!this.showLogs) {
16
+ return;
17
+ }
18
+
19
+ console.log(msg);
20
+ };
21
+
22
+ error = function(msg) {
23
+ if (!this.showLogs) {
24
+ return;
25
+ }
26
+
27
+ console.error(msg);
28
+ };
29
+
30
+ warning = function(msg) {
31
+ if (!this.showLogs) {
32
+ return;
33
+ }
34
+
35
+ console.warn(msg);
36
+ }
37
+ }
38
+
39
+ const logger = new Logger();
40
+ export default logger;
@@ -0,0 +1,75 @@
1
+ /* global shaka */
2
+ /* global videojs */
3
+ /* global dashjs */
4
+ /* global Hls */
5
+
6
+ /**
7
+ * Stateless. Functions that detect players somehow.
8
+ * @class
9
+ */
10
+
11
+ class PlayerDetector {
12
+
13
+ static isBitmovinVersionPre7 = function(player) {
14
+ if (PlayerDetector.isDashjs(player)) {
15
+ return false;
16
+ }
17
+
18
+ if (typeof player.getVersion === 'function') {
19
+ return player.getVersion() < '7';
20
+ }
21
+
22
+ return false;
23
+ };
24
+
25
+ static isBitmovinVersion7Plus = function(player) {
26
+ if (typeof player.version === 'string') {
27
+ return player.version >= '7';
28
+ }
29
+
30
+ return false;
31
+ };
32
+
33
+ static isVideoJs = function(player) {
34
+ if (typeof videojs === 'function') {
35
+ try {
36
+ if (videojs(player.id_) === player) {
37
+ return true;
38
+ }
39
+ } catch (err) {}
40
+ }
41
+ return false;
42
+ }
43
+
44
+ static isShaka(player) {
45
+
46
+ if (!window.shaka) {
47
+ // Shaka is not defined installed (must be loaded before analytics module)
48
+ return false;
49
+ }
50
+
51
+ return (
52
+ typeof shaka.Player === 'function' && player.constructor === shaka.Player
53
+ );
54
+
55
+ }
56
+
57
+ static isDashjs(player) {
58
+ return typeof player.addABRCustomRule === 'function';
59
+ }
60
+
61
+ static isHlsjs(player) {
62
+
63
+ if (!window.Hls) {
64
+ // Hls.js is not defined installed (must be loaded before analytics module)
65
+ return false;
66
+ }
67
+
68
+ return (
69
+ typeof window.Hls === 'function' && player.constructor === window.Hls
70
+ );
71
+ return false;
72
+ }
73
+ }
74
+
75
+ export default PlayerDetector;
@@ -0,0 +1,22 @@
1
+ import HttpCall from './HttpCall';
2
+ import {ANALYTICS_BACKEND_BASE_URL} from './Settings';
3
+
4
+ class PlayerInitCall extends HttpCall{
5
+ static analyticsServerUrl = ANALYTICS_BACKEND_BASE_URL;
6
+
7
+ sendRequest = function(sample, callback) {
8
+ sample.event_family = 'player_init';
9
+ this.get(PlayerInitCall.analyticsServerUrl, sample, callback);
10
+ };
11
+
12
+ sendRequestSynchronous = function(sample, callback) {
13
+ sample.event_family = 'player_init';
14
+ this.get(PlayerInitCall.analyticsServerUrl, sample, callback, false);
15
+ };
16
+
17
+ getAnalyticsServerUrl = function() {
18
+ return PlayerInitCall.analyticsServerUrl;
19
+ }
20
+ }
21
+
22
+ export default PlayerInitCall;
@@ -0,0 +1,22 @@
1
+ import HttpCall from './HttpCall';
2
+ import {ANALYTICS_BACKEND_BASE_URL} from './Settings';
3
+
4
+ class SessionCreationCall extends HttpCall{
5
+ static analyticsServerUrl = ANALYTICS_BACKEND_BASE_URL;
6
+
7
+ sendRequest = function(sample, callback) {
8
+ sample.event_family = 'session';
9
+ this.get(SessionCreationCall.analyticsServerUrl, sample, callback);
10
+ };
11
+
12
+ sendRequestSynchronous = function(sample, callback) {
13
+ sample.event_family = 'session';
14
+ this.get(SessionCreationCall.analyticsServerUrl, sample, callback, false);
15
+ };
16
+
17
+ getAnalyticsServerUrl = function() {
18
+ return SessionCreationCall.analyticsServerUrl;
19
+ }
20
+ }
21
+
22
+ export default SessionCreationCall;
@@ -0,0 +1,3 @@
1
+ export const MESSAGE_NAMESPACE = 'urn:x-cast:com.gumlet.ingest.cast';
2
+ export const ANALYTICS_BACKEND_BASE_URL = 'https://ingest.gumlytics.com';
3
+ export const HEARTBEAT_THRESHOLD = 10000;
@@ -0,0 +1,195 @@
1
+ const validString = function(string) {
2
+ return (string != undefined && typeof string == 'string');
3
+ };
4
+
5
+ const validBoolean = function(boolean) {
6
+ return (boolean != undefined && typeof boolean == 'boolean');
7
+ };
8
+
9
+ const validNumber = function(number) {
10
+ return (number != undefined && typeof number == 'number');
11
+ };
12
+
13
+ const sanitizePath = function(path) {
14
+ return path.replace(/\/$/g, '');
15
+ };
16
+
17
+ const calculateTime = function(time) {
18
+ time = time * 1000;
19
+ return Math.round(time);
20
+ };
21
+
22
+ const getCurrentTimestamp = function() {
23
+ return new Date().getTime();
24
+ };
25
+
26
+ const getDurationFromTimestampToNow = function(timestamp) {
27
+ return getCurrentTimestamp() - timestamp;
28
+ };
29
+
30
+ const uuidv4 = function() {
31
+ return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
32
+ (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16).toUpperCase()
33
+ );
34
+ }
35
+
36
+ const getCookie = function(cname) {
37
+ const name = cname + '=';
38
+ const ca = document.cookie.split(';');
39
+ let item = "";
40
+ for (let i = 0; i < ca.length; i++) {
41
+ let c = ca[i];
42
+ while (c.charAt(0) == ' ') {
43
+ c = c.substring(1);
44
+ }
45
+ if (c.indexOf(name) == 0) {
46
+ item = c.substring(name.length, c.length);
47
+ }
48
+ }
49
+
50
+ if (!item) {
51
+ try {
52
+ item = localStorage.getItem(cname);
53
+ } catch (error) {
54
+ return "";
55
+ }
56
+ // check if localstorage has the item
57
+ let data = null;
58
+ if (item){
59
+ // try parsing the values as a JSON
60
+ try{
61
+ data = JSON.parse(item);
62
+ } catch (e) {
63
+ return "";
64
+ }
65
+ }else{
66
+ return "";
67
+ }
68
+
69
+ // check if loaded data has expires if not return none
70
+ let expiresAt = null;
71
+ if (data.expires) {
72
+ expiresAt = new Date(data.expires);
73
+ }else{
74
+ return "";
75
+ }
76
+
77
+ // Check if expiresAt is a valid dateTime object
78
+ if (Object.prototype.toString.call(expiresAt) === "[object Date]") {
79
+ // it is a date
80
+ if (isNaN(expiresAt)) {
81
+ // date object is not valid
82
+ return "";
83
+ } else {
84
+ // date object is valid
85
+ }
86
+ } else {
87
+ return "";
88
+ }
89
+
90
+ // Check if expires at is greater than the current time
91
+ if (expiresAt.getTime() > (new Date()).getTime()) {
92
+ // if data has value then return it else return ""
93
+ item = data.value ? data.value : "";
94
+ }else{
95
+ return "";
96
+ }
97
+ }
98
+
99
+ // return read data
100
+ return item;
101
+ };
102
+
103
+ const setCookie = function(cname, expiry_mins=30, value=null) {
104
+ let date = new Date();
105
+ date.setTime(date.getTime() + (expiry_mins*60*1000));
106
+ let id = !value ? uuidv4() : value;
107
+ try {
108
+ document.cookie = cname+'=' + id +'; expires='+date.toUTCString()+'; path=/';
109
+ localStorage.setItem(cname, JSON.stringify({
110
+ expires: date.getTime(),
111
+ value: id
112
+ }));
113
+ } catch (error) {
114
+ }
115
+ return id;
116
+ };
117
+
118
+ const noOp = function() {
119
+
120
+ };
121
+
122
+ const times = function (fn, times) {
123
+ let count = 0;
124
+ let retVal;
125
+ return function () {
126
+ if (count >= times) {
127
+ return retVal;
128
+ }
129
+ retVal = fn.apply(null, arguments);
130
+ count++;
131
+ return retVal;
132
+ };
133
+ };
134
+
135
+ const once = function (fn) {
136
+ return times(fn, 1);
137
+ };
138
+
139
+ const getHiddenProp = function() {
140
+ const prefixes = ['webkit','moz','ms','o'];
141
+ if ('hidden' in document) { return 'hidden'; }
142
+ for (let i = 0; i < prefixes.length; i++){
143
+ if ((prefixes[i] + 'Hidden') in document) {
144
+ return prefixes[i] + 'Hidden';
145
+ }
146
+ }
147
+ return null;
148
+ };
149
+
150
+ const getCustomDataString = function(customData) {
151
+ if (typeof customData === 'object') {
152
+ return JSON.stringify(customData);
153
+ } else if (typeof customData === 'function') {
154
+ return getCustomDataString(customData());
155
+ } else if (typeof customData === 'undefined') {
156
+ return customData;
157
+ } else if (typeof customData !== 'string') {
158
+ return String(customData);
159
+ }
160
+
161
+ return customData;
162
+ };
163
+
164
+ const jsonToQueryString = function(json) {
165
+ return '?' +
166
+ Object.keys(json).map(function(key) {
167
+ return encodeURIComponent(key) + '=' +
168
+ encodeURIComponent(json[key]);
169
+ }).join('&');
170
+ }
171
+
172
+ const currentDateTimeFormatString = function() {
173
+ const currentDateTime = new Date();
174
+ return currentDateTime.toISOString();
175
+ }
176
+
177
+ export default {
178
+ validString,
179
+ validBoolean,
180
+ validNumber,
181
+ sanitizePath,
182
+ calculateTime,
183
+ getCurrentTimestamp,
184
+ getDurationFromTimestampToNow,
185
+ uuidv4,
186
+ getCookie,
187
+ setCookie,
188
+ noOp,
189
+ times,
190
+ once,
191
+ getHiddenProp,
192
+ getCustomDataString,
193
+ jsonToQueryString,
194
+ currentDateTimeFormatString
195
+ };