@qikdev/sdk 1.0.2 → 1.0.5
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.
- package/README.md +1 -1
- package/dist/{docs/access.html → access.html} +353 -20
- package/dist/api.html +444 -0
- package/dist/{docs/auth.html → auth.html} +14 -14
- package/dist/cache.html +351 -0
- package/dist/{docs/content.html → content.html} +46 -21
- package/dist/{docs/files.html → files.html} +147 -6
- package/dist/{docs/filter.html → filter.html} +9 -9
- package/dist/geo.html +1029 -0
- package/dist/global.html +240 -0
- package/dist/index.html +96 -0
- package/dist/main.js +2 -3
- package/dist/module-QikStorage-CookieStorageAdapter.html +407 -0
- package/dist/module-QikStorage-LocalStorageAdapter.html +193 -0
- package/dist/module-QikStorage-StorageAdapter.html +977 -0
- package/dist/module-QikStorage.html +433 -0
- package/dist/qik.access.js.html +904 -0
- package/dist/qik.api.js.html +409 -0
- package/dist/{docs/qik.auth.js.html → qik.auth.js.html} +142 -104
- package/dist/qik.cache.js.html +125 -0
- package/dist/qik.content.js.html +967 -0
- package/dist/qik.core.js.html +322 -0
- package/dist/qik.files.js.html +249 -0
- package/dist/{docs/qik.filter.js.html → qik.filter.js.html} +3 -3
- package/dist/qik.geo.js.html +963 -0
- package/dist/{docs/qik.socket.js.html → qik.socket.js.html} +53 -12
- package/dist/qik.storage.js.html +375 -0
- package/dist/qik.system.js.html +117 -0
- package/dist/qik.utils.js.html +1548 -0
- package/dist/{docs/socket.html → socket.html} +7 -7
- package/dist/{docs/styles → styles}/jsdoc.css +2 -2
- package/dist/system.html +197 -0
- package/dist/utils.html +4422 -0
- package/package.json +2 -2
- package/src/api/qik.filter.js +1 -1
- package/src/api/qik.geo.js +1 -1
- package/src/api/qik.socket.js +18 -12
- package/src/api/qik.utils.js +6 -0
- package/src/version.js +1 -1
- package/dist/docs/api.html +0 -1356
- package/dist/docs/cache.html +0 -351
- package/dist/docs/index.html +0 -96
- package/dist/docs/qik.access.js.html +0 -790
- package/dist/docs/qik.api.js.html +0 -511
- package/dist/docs/qik.cache.js.html +0 -131
- package/dist/docs/qik.content.js.html +0 -918
- package/dist/docs/qik.core.js.html +0 -301
- package/dist/docs/qik.files.js.html +0 -219
- package/dist/docs/qik.system.js.html +0 -117
- package/dist/docs/qik.utils.js.html +0 -1467
- package/dist/docs/system.html +0 -197
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Bold.eot +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Bold.ttf +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Bold.woff +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Bold.woff2 +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Regular.eot +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Regular.ttf +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Regular.woff +0 -0
- /package/dist/{docs/fonts → fonts}/Montserrat/Montserrat-Regular.woff2 +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- /package/dist/{docs/fonts → fonts}/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- /package/dist/{docs/scripts → scripts}/collapse.js +0 -0
- /package/dist/{docs/scripts → scripts}/linenumber.js +0 -0
- /package/dist/{docs/scripts → scripts}/nav.js +0 -0
- /package/dist/{docs/scripts → scripts}/polyfill.js +0 -0
- /package/dist/{docs/scripts → scripts}/prettify/Apache-License-2.0.txt +0 -0
- /package/dist/{docs/scripts → scripts}/prettify/lang-css.js +0 -0
- /package/dist/{docs/scripts → scripts}/prettify/prettify.js +0 -0
- /package/dist/{docs/scripts → scripts}/search.js +0 -0
- /package/dist/{docs/styles → styles}/prettify.css +0 -0
|
@@ -0,0 +1,1548 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>qik.utils.js - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
|
|
21
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
22
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
23
|
+
<div class="navicon"></div>
|
|
24
|
+
</label>
|
|
25
|
+
|
|
26
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
27
|
+
|
|
28
|
+
<nav >
|
|
29
|
+
|
|
30
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="access.html">access</a><ul class='methods'><li data-type='method'><a href="access.html#.actionableScopes">actionableScopes</a></li><li data-type='method'><a href="access.html#.allPermissions">allPermissions</a></li><li data-type='method'><a href="access.html#.allPermissionTypes">allPermissionTypes</a></li><li data-type='method'><a href="access.html#.allUserScopes">allUserScopes</a></li><li data-type='method'><a href="access.html#.canCreate">canCreate</a></li><li data-type='method'><a href="access.html#.canDeleteItem">canDeleteItem</a></li><li data-type='method'><a href="access.html#.canEditItem">canEditItem</a></li><li data-type='method'><a href="access.html#.canEraseItem">canEraseItem</a></li><li data-type='method'><a href="access.html#.canKnowOf">canKnowOf</a></li><li data-type='method'><a href="access.html#.canListItem">canListItem</a></li><li data-type='method'><a href="access.html#.canRestoreItem">canRestoreItem</a></li><li data-type='method'><a href="access.html#.canViewItem">canViewItem</a></li><li data-type='method'><a href="access.html#.checkActionAccess">checkActionAccess</a></li><li data-type='method'><a href="access.html#.getAllDescendants">getAllDescendants</a></li><li data-type='method'><a href="access.html#.has">has</a></li><li data-type='method'><a href="access.html#.hasFeature">hasFeature</a></li><li data-type='method'><a href="access.html#.hashPermissions">hashPermissions</a></li><li data-type='method'><a href="access.html#.isAdministrator">isAdministrator</a></li><li data-type='method'><a href="access.html#.isAssignee">isAssignee</a></li><li data-type='method'><a href="access.html#.isOwner">isOwner</a></li></ul></li><li><a href="api.html">api</a><ul class='methods'><li data-type='method'><a href="api.html#.generateEndpointURL">generateEndpointURL</a></li></ul></li><li><a href="auth.html">auth</a><ul class='methods'><li data-type='method'><a href="auth.html#.changeOrganisation">changeOrganisation</a></li><li data-type='method'><a href="auth.html#.ensureValidToken">ensureValidToken</a></li><li data-type='method'><a href="auth.html#.getCurrentToken">getCurrentToken</a></li><li data-type='method'><a href="auth.html#.getCurrentUser">getCurrentUser</a></li><li data-type='method'><a href="auth.html#.impersonate">impersonate</a></li><li data-type='method'><a href="auth.html#.login">login</a></li><li data-type='method'><a href="auth.html#.logout">logout</a></li><li data-type='method'><a href="auth.html#.retrieveUserFromResetToken">retrieveUserFromResetToken</a></li><li data-type='method'><a href="auth.html#.sendResetPasswordRequest">sendResetPasswordRequest</a></li><li data-type='method'><a href="auth.html#.set">set</a></li><li data-type='method'><a href="auth.html#.sync">sync</a></li><li data-type='method'><a href="auth.html#.updateUserWithToken">updateUserWithToken</a></li></ul></li><li><a href="cache.html">cache</a><ul class='methods'><li data-type='method'><a href="cache.html#.get">get</a></li><li data-type='method'><a href="cache.html#.reset">reset</a></li></ul></li><li><a href="content.html">content</a><ul class='methods'><li data-type='method'><a href="content.html#.create">create</a></li><li data-type='method'><a href="content.html#.delete">delete</a></li><li data-type='method'><a href="content.html#.get">get</a></li><li data-type='method'><a href="content.html#.getFromSlug">getFromSlug</a></li><li data-type='method'><a href="content.html#.glossary">glossary</a></li><li data-type='method'><a href="content.html#.list">list</a></li><li data-type='method'><a href="content.html#.patch">patch</a></li><li data-type='method'><a href="content.html#.restore">restore</a></li><li data-type='method'><a href="content.html#.scopeGlossary">scopeGlossary</a></li><li data-type='method'><a href="content.html#.update">update</a></li><li data-type='method'><a href="content.html#.validateField">validateField</a></li><li data-type='method'><a href="content.html#.variables">variables</a></li></ul></li><li><a href="files.html">files</a><ul class='methods'><li data-type='method'><a href="files.html#.downloadUrl">downloadUrl</a></li><li data-type='method'><a href="files.html#.duration">duration</a></li><li data-type='method'><a href="files.html#.filesize">filesize</a></li><li data-type='method'><a href="files.html#.getBinaryTypeFromMime">getBinaryTypeFromMime</a></li><li data-type='method'><a href="files.html#.mediaUrl">mediaUrl</a></li></ul></li><li><a href="filter.html">filter</a><ul class='methods'><li data-type='method'><a href="filter.html#.activeFilterComparators">activeFilterComparators</a></li><li data-type='method'><a href="filter.html#.activeFilterKeys">activeFilterKeys</a></li><li data-type='method'><a href="filter.html#.activeFilterOperators">activeFilterOperators</a></li><li data-type='method'><a href="filter.html#.activeFilters">activeFilters</a></li><li data-type='method'><a href="filter.html#.activeFilterValues">activeFilterValues</a></li><li data-type='method'><a href="filter.html#.filterChangeString">filterChangeString</a></li><li data-type='method'><a href="filter.html#.isValidFilter">isValidFilter</a></li></ul></li><li><a href="geo.html">geo</a><ul class='methods'><li data-type='method'><a href="geo.html#.distance">distance</a></li><li data-type='method'><a href="geo.html#.getDefaultCountry">getDefaultCountry</a></li><li data-type='method'><a href="geo.html#.getDefaultTimezone">getDefaultTimezone</a></li><li data-type='method'><a href="geo.html#.getPosition">getPosition</a></li><li data-type='method'><a href="geo.html#.stopWatchPosition">stopWatchPosition</a></li><li data-type='method'><a href="geo.html#.watchPosition">watchPosition</a></li></ul></li><li><a href="module-QikStorage-CookieStorageAdapter.html">CookieStorageAdapter</a><ul class='methods'><li data-type='method'><a href="module-QikStorage-CookieStorageAdapter.html#getCookieOptions">getCookieOptions</a></li><li data-type='method'><a href="module-QikStorage-CookieStorageAdapter.html#isCookieMode">isCookieMode</a></li></ul></li><li><a href="module-QikStorage-LocalStorageAdapter.html">LocalStorageAdapter</a></li><li><a href="module-QikStorage-StorageAdapter.html">StorageAdapter</a><ul class='methods'><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#clearUser">clearUser</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getAccessToken">getAccessToken</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getRefreshToken">getRefreshToken</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getTokenExpiry">getTokenExpiry</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getUser">getUser</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#isAvailable">isAvailable</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#setUser">setUser</a></li></ul></li><li><a href="socket.html">socket</a><ul class='methods'><li data-type='method'><a href="socket.html#.channel">channel</a></li><li data-type='method'><a href="socket.html#.close">close</a></li><li data-type='method'><a href="socket.html#.connect">connect</a></li><li data-type='method'><a href="socket.html#.reconnect">reconnect</a></li><li data-type='method'><a href="socket.html#.subscribe">subscribe</a></li><li data-type='method'><a href="socket.html#.unsubscribe">unsubscribe</a></li></ul></li><li><a href="system.html">system</a><ul class='methods'><li data-type='method'><a href="system.html#.countries">countries</a></li></ul></li><li><a href="utils.html">utils</a><ul class='methods'><li data-type='method'><a href="utils.html#.cleanValue">cleanValue</a></li><li data-type='method'><a href="utils.html#.comma">comma</a></li><li data-type='method'><a href="utils.html#.errorMessage">errorMessage</a></li><li data-type='method'><a href="utils.html#.exists">exists</a></li><li data-type='method'><a href="utils.html#.extractFromArray">extractFromArray</a></li><li data-type='method'><a href="utils.html#.formatCurrency">formatCurrency</a></li><li data-type='method'><a href="utils.html#.getTypeFromID">getTypeFromID</a></li><li data-type='method'><a href="utils.html#.guid">guid</a></li><li data-type='method'><a href="utils.html#.hash">hash</a></li><li data-type='method'><a href="utils.html#.id">id</a></li><li data-type='method'><a href="utils.html#.ids">ids</a></li><li data-type='method'><a href="utils.html#.isValidEmailAddress">isValidEmailAddress</a></li><li data-type='method'><a href="utils.html#.loadExternalScript">loadExternalScript</a></li><li data-type='method'><a href="utils.html#.loadExternalStyle">loadExternalStyle</a></li><li data-type='method'><a href="utils.html#.machineName">machineName</a></li><li data-type='method'><a href="utils.html#.mapParameters">mapParameters</a></li><li data-type='method'><a href="utils.html#.matchInArray">matchInArray</a></li><li data-type='method'><a href="utils.html#.parseBoolean">parseBoolean</a></li><li data-type='method'><a href="utils.html#.parseDate">parseDate</a></li><li data-type='method'><a href="utils.html#.parseEmail">parseEmail</a></li><li data-type='method'><a href="utils.html#.parseInt">parseInt</a></li><li data-type='method'><a href="utils.html#.parseNumber">parseNumber</a></li><li data-type='method'><a href="utils.html#.parseURL">parseURL</a></li></ul></li></ul><h3>Modules</h3><ul><li><a href="module-QikStorage.html">QikStorage</a><ul class='methods'><li data-type='method'><a href="module-QikStorage.html#.createStorageAdapter">createStorageAdapter</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#EventDispatcher">EventDispatcher</a></li></ul>
|
|
31
|
+
</nav>
|
|
32
|
+
|
|
33
|
+
<div id="main">
|
|
34
|
+
|
|
35
|
+
<h1 class="page-title">qik.utils.js</h1>
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
<section>
|
|
44
|
+
<article>
|
|
45
|
+
<pre class="prettyprint source linenums"><code>import _get from "lodash.get";
|
|
46
|
+
import _camelCase from "lodash.camelcase";
|
|
47
|
+
import { isBrowser, isNode } from "browser-or-node";
|
|
48
|
+
|
|
49
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @name utils
|
|
53
|
+
* @classdesc Utility helper functions — id, ids, hashing, parsing, cleaning, and other general-purpose helpers
|
|
54
|
+
* @class
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
const service = {};
|
|
58
|
+
|
|
59
|
+
////////////////////////////////////
|
|
60
|
+
|
|
61
|
+
const loadedExternalScripts = {};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A function that dynamically include an external javascript resource
|
|
65
|
+
* ensuring that it will only be included once
|
|
66
|
+
* @alias utils.loadExternalScript
|
|
67
|
+
* @param {String} url The url of the external script
|
|
68
|
+
* @return {Promise} A promise that will be resolved once the script has been loaded
|
|
69
|
+
* @example
|
|
70
|
+
*
|
|
71
|
+
* await sdk.utils.loadExternalScript('https://cdn.javascript.com/external/script.js');
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
service.loadExternalScript = function (url) {
|
|
75
|
+
// If we already have a promise
|
|
76
|
+
if (loadedExternalScripts[url]) {
|
|
77
|
+
// return the existing promise
|
|
78
|
+
return loadedExternalScripts[url];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Create a new promise
|
|
82
|
+
const promise = (loadedExternalScripts[url] = new Promise(createNewScript));
|
|
83
|
+
|
|
84
|
+
function createNewScript(resolve, reject) {
|
|
85
|
+
if (!document) {
|
|
86
|
+
delete loadedExternalScripts[url];
|
|
87
|
+
return reject("document is undefined");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//////////////////////////////////////
|
|
91
|
+
|
|
92
|
+
var script = document.createElement("script");
|
|
93
|
+
script.type = "text/javascript";
|
|
94
|
+
script.async = true;
|
|
95
|
+
script.onload = function () {
|
|
96
|
+
console.log("Loaded external script", url);
|
|
97
|
+
return resolve(url);
|
|
98
|
+
};
|
|
99
|
+
script.src = url;
|
|
100
|
+
|
|
101
|
+
// Inject it into the document's <head> tag
|
|
102
|
+
document.head.appendChild(script);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return promise;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const loadedExternalStyles = {};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A function that dynamically include an external css resource
|
|
112
|
+
* ensuring that it will only be included once
|
|
113
|
+
* @alias utils.loadExternalStyle
|
|
114
|
+
* @param {String} url The url of the external css
|
|
115
|
+
* @return {Promise} A promise that will be resolved once the css has been loaded
|
|
116
|
+
* @example
|
|
117
|
+
*
|
|
118
|
+
* await sdk.utils.loadExternalStyle('https://cdn.css.com/external/style.css');
|
|
119
|
+
*/
|
|
120
|
+
service.loadExternalStyle = function (url) {
|
|
121
|
+
const promise = new Promise(createNewScript);
|
|
122
|
+
|
|
123
|
+
function createNewScript(resolve, reject) {
|
|
124
|
+
if (!document) {
|
|
125
|
+
return reject("document is undefined");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (loadedExternalStyles[url]) {
|
|
129
|
+
return resolve(url);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Avoid duplicate scripts
|
|
133
|
+
loadedExternalStyles[url] = true;
|
|
134
|
+
|
|
135
|
+
//////////////////////////////////////
|
|
136
|
+
|
|
137
|
+
var script = document.createElement("link");
|
|
138
|
+
script.setAttribute("rel", "stylesheet");
|
|
139
|
+
script.setAttribute("type", "text/css");
|
|
140
|
+
script.setAttribute("href", url);
|
|
141
|
+
script.onload = function () {
|
|
142
|
+
console.log("Loaded external stylesheet", url);
|
|
143
|
+
return resolve(url);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Inject it into the document's <head> tag
|
|
147
|
+
document.head.appendChild(script);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return promise;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* A helper function for checking whether a value is truthy/falsy
|
|
157
|
+
* @alias utils.exists
|
|
158
|
+
* @param {Anything} value The value to check
|
|
159
|
+
* @return {Boolean} whether the value is truthy
|
|
160
|
+
* @example
|
|
161
|
+
*
|
|
162
|
+
* sdk.utils.exists('undefined'); // false
|
|
163
|
+
* sdk.utils.exists([]); // true
|
|
164
|
+
* sdk.utils.exists(''); // false
|
|
165
|
+
* sdk.utils.exists(undefined); // false
|
|
166
|
+
*/
|
|
167
|
+
service.exists = function (value) {
|
|
168
|
+
var isUndefinedOrNull;
|
|
169
|
+
|
|
170
|
+
////////////////////////
|
|
171
|
+
|
|
172
|
+
if (Array.isArray(value)) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
////////////////////////
|
|
177
|
+
|
|
178
|
+
if (value === 0) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
////////////////////////
|
|
183
|
+
|
|
184
|
+
switch (typeof value) {
|
|
185
|
+
case "undefined":
|
|
186
|
+
case "null":
|
|
187
|
+
isUndefinedOrNull = true;
|
|
188
|
+
break;
|
|
189
|
+
default:
|
|
190
|
+
var string = String(value).toLowerCase();
|
|
191
|
+
switch (string) {
|
|
192
|
+
case "":
|
|
193
|
+
case "undefined":
|
|
194
|
+
case "null":
|
|
195
|
+
isUndefinedOrNull = true;
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return !!!isUndefinedOrNull;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
//////////////////////////////////
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A helper function for getting a javascript date object from some input
|
|
208
|
+
* returns undefined if it can not be parsed
|
|
209
|
+
* @alias utils.parseDate
|
|
210
|
+
* @param {String|Number} input The value to parse as a date
|
|
211
|
+
* @return {Date} the javascript date object
|
|
212
|
+
* @example
|
|
213
|
+
*
|
|
214
|
+
* sdk.utils.parseDate(input);
|
|
215
|
+
*/
|
|
216
|
+
service.parseDate = function (input) {
|
|
217
|
+
if (!input) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (input instanceof Date) {
|
|
222
|
+
return input;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
//Attempt to create a date
|
|
226
|
+
var d = new Date(input);
|
|
227
|
+
var isValid = d instanceof Date && !isNaN(d);
|
|
228
|
+
|
|
229
|
+
if (isValid) {
|
|
230
|
+
return d;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* A helper function for getting a full url string from some input
|
|
238
|
+
* @alias utils.parseURL
|
|
239
|
+
* @param {String} input The input value
|
|
240
|
+
* @return {String} the fully parsed URL
|
|
241
|
+
* @example
|
|
242
|
+
*
|
|
243
|
+
* sdk.utils.parseURL('google.com'); // Returns https://google.com
|
|
244
|
+
* sdk.utils.parseURL('mailto:hello@qik.dev'); // Returns 'mailto:hello@qik.dev'
|
|
245
|
+
* sdk.utils.parseURL('://hello.com'); // Returns '://hello.com'
|
|
246
|
+
* sdk.utils.parseURL('hello@email.com'); // Returns 'mailto:hello@email.com'
|
|
247
|
+
*/
|
|
248
|
+
service.parseURL = function (string) {
|
|
249
|
+
if (!string) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const relative = string.startsWith("/");
|
|
254
|
+
if (relative) {
|
|
255
|
+
return string;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (string.startsWith("://")) {
|
|
259
|
+
return string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (string.startsWith("mailto:")) {
|
|
263
|
+
return string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (string.startsWith("tel:")) {
|
|
267
|
+
return string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (string.startsWith("sms:")) {
|
|
271
|
+
return string;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
//////////////////////////////////
|
|
275
|
+
//If someone entered an email by accident
|
|
276
|
+
var email = service.parseEmail(string);
|
|
277
|
+
//Convert it to a mailto link
|
|
278
|
+
if (email && email === string) {
|
|
279
|
+
return `mailto:${email}`;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
//////////////////////////////////
|
|
283
|
+
|
|
284
|
+
const withHttp = (string) =>
|
|
285
|
+
!/^https?:\/\//i.test(string) ? `http://${string}` : string;
|
|
286
|
+
string = withHttp(string);
|
|
287
|
+
//TODO: test this more.
|
|
288
|
+
string = string.replace(/\s/g, "");
|
|
289
|
+
|
|
290
|
+
var valid = RegExp(
|
|
291
|
+
"(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-@]*)?(\\#[-a-z\\d_@]*)?$",
|
|
292
|
+
"i",
|
|
293
|
+
).test(string);
|
|
294
|
+
|
|
295
|
+
if (!valid) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
///////////////////////////
|
|
300
|
+
|
|
301
|
+
return withHttp(string);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
///////////////////////////////////////////////
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* A helper function for getting a number from some input
|
|
308
|
+
* @alias utils.parseNumber
|
|
309
|
+
* @param {String} value The input value
|
|
310
|
+
* @param {Number} decimalPoints The number of decimal points to round to
|
|
311
|
+
* @return {Number} the parsed number value
|
|
312
|
+
* @example
|
|
313
|
+
*
|
|
314
|
+
* sdk.utils.parseNumber('123'); // Returns 123
|
|
315
|
+
* sdk.utils.parseNumber('75.501', 2); // Returns 75.5
|
|
316
|
+
* sdk.utils.parseNumber(''); // Returns 0
|
|
317
|
+
* sdk.utils.parseNumber(null); // Returns 0
|
|
318
|
+
* sdk.utils.parseNumber(); // Returns 0
|
|
319
|
+
*/
|
|
320
|
+
service.parseNumber = function (input, decimalPoints) {
|
|
321
|
+
if (!input) {
|
|
322
|
+
return 0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
input = Number(input);
|
|
326
|
+
if (isNaN(input)) {
|
|
327
|
+
return 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (decimalPoints) {
|
|
331
|
+
var str = input.toFixed(decimalPoints);
|
|
332
|
+
input = service.parseNumber(str);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return input;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* A helper function for getting a number from some input
|
|
340
|
+
* @alias utils.isValidEmailAddress
|
|
341
|
+
* @param {String} emailAddress The email to validate
|
|
342
|
+
* @return {Boolean} whether or not the input is a valid email address
|
|
343
|
+
* @example
|
|
344
|
+
*
|
|
345
|
+
* sdk.utils.isValidEmailAddress('123.com'); // Returns false
|
|
346
|
+
* sdk.utils.isValidEmailAddress('hello@world.com'); // Returns true
|
|
347
|
+
* sdk.utils.isValidEmailAddress('something@special.io'); // Returns true
|
|
348
|
+
*/
|
|
349
|
+
service.isValidEmailAddress = function (email) {
|
|
350
|
+
var tester =
|
|
351
|
+
/^[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;
|
|
352
|
+
|
|
353
|
+
if (!email) return false;
|
|
354
|
+
|
|
355
|
+
var emailParts = email.split("@");
|
|
356
|
+
|
|
357
|
+
if (emailParts.length !== 2) return false;
|
|
358
|
+
|
|
359
|
+
var account = emailParts[0];
|
|
360
|
+
var address = emailParts[1];
|
|
361
|
+
|
|
362
|
+
if (account.length > 64) return false;
|
|
363
|
+
else if (address.length > 255) return false;
|
|
364
|
+
|
|
365
|
+
var domainParts = address.split(".");
|
|
366
|
+
if (
|
|
367
|
+
domainParts.some(function (part) {
|
|
368
|
+
return part.length > 63;
|
|
369
|
+
})
|
|
370
|
+
)
|
|
371
|
+
return false;
|
|
372
|
+
|
|
373
|
+
if (!tester.test(email)) return false;
|
|
374
|
+
|
|
375
|
+
return true;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* A helper function for getting a formatted email address
|
|
380
|
+
* @alias utils.parseEmail
|
|
381
|
+
* @param {String} emailAddress The input to parse as an email
|
|
382
|
+
* @return {String|Boolean} a valid email address in lowercase, or false if parse is not possible
|
|
383
|
+
* @example
|
|
384
|
+
*
|
|
385
|
+
* sdk.utils.parseEmail('ToMack@gmail.com'); // returns 'tomack@gmail.com'
|
|
386
|
+
* sdk.utils.isValidEmailAddress('hello.world.com'); // Returns false
|
|
387
|
+
*/
|
|
388
|
+
service.parseEmail = function (input) {
|
|
389
|
+
if (!input) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
var lowercase = String(input).toLowerCase();
|
|
394
|
+
var valid = service.isValidEmailAddress(lowercase);
|
|
395
|
+
|
|
396
|
+
if (!valid) {
|
|
397
|
+
return false;
|
|
398
|
+
} else {
|
|
399
|
+
return lowercase;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
//////////////////////////////////
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* A helper function for getting an integer
|
|
407
|
+
* @alias utils.parseInt
|
|
408
|
+
* @param {String|Number} input The input to parse as an integer
|
|
409
|
+
* @return {Integer} the resulting integer or 0
|
|
410
|
+
* @example
|
|
411
|
+
*
|
|
412
|
+
* sdk.utils.parseInt('134'); // returns 134
|
|
413
|
+
* sdk.utils.parseInt('cows'); // returns 0
|
|
414
|
+
* sdk.utils.parseInt(); // returns 0
|
|
415
|
+
*/
|
|
416
|
+
service.parseInt = function (input) {
|
|
417
|
+
if (!input) {
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
input = parseInt(input);
|
|
422
|
+
if (isNaN(input)) {
|
|
423
|
+
return 0;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return input;
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* A helper function for cleaning an input value to match
|
|
431
|
+
* a required type
|
|
432
|
+
* @alias utils.cleanValue
|
|
433
|
+
* @param {*} data The input to clean
|
|
434
|
+
* @param {String} type The data type to parse
|
|
435
|
+
* @param {Object} options Additional options for parsing
|
|
436
|
+
* @return {*} the resulting cleaned value
|
|
437
|
+
* @example
|
|
438
|
+
*
|
|
439
|
+
* sdk.utils.cleanValue({_id:'1234', title:'Item'...}, 'reference'); // returns '1234'
|
|
440
|
+
* sdk.utils.cleanValue('true', 'boolean'); // returns true
|
|
441
|
+
* sdk.utils.cleanValue('Mr Rogers House', 'key'); // returns 'mrRogersHouse';
|
|
442
|
+
* sdk.utils.cleanValue('Hello.World@email.COM', 'email'); // returns 'hello.world@email.com';
|
|
443
|
+
*/
|
|
444
|
+
service.cleanValue = function (data, type, options) {
|
|
445
|
+
if (!options) {
|
|
446
|
+
options = {};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
////////////////////////
|
|
450
|
+
|
|
451
|
+
var noInputValue = service.exists(data);
|
|
452
|
+
if (options.strict && noInputValue && type != "boolean") {
|
|
453
|
+
return data;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
////////////////////////
|
|
457
|
+
|
|
458
|
+
switch (type) {
|
|
459
|
+
case "reference":
|
|
460
|
+
return service.id(data, true);
|
|
461
|
+
break;
|
|
462
|
+
case "boolean":
|
|
463
|
+
return service.parseBoolean(data);
|
|
464
|
+
break;
|
|
465
|
+
case "url":
|
|
466
|
+
return service.parseURL(data);
|
|
467
|
+
break;
|
|
468
|
+
case "key":
|
|
469
|
+
return service.machineName(data);
|
|
470
|
+
break;
|
|
471
|
+
case "email":
|
|
472
|
+
return service.parseEmail(data);
|
|
473
|
+
break;
|
|
474
|
+
case "date":
|
|
475
|
+
var parsed = service.parseDate(data, options);
|
|
476
|
+
|
|
477
|
+
if (parsed === undefined) {
|
|
478
|
+
return;
|
|
479
|
+
} else {
|
|
480
|
+
return parsed;
|
|
481
|
+
}
|
|
482
|
+
break;
|
|
483
|
+
case "number":
|
|
484
|
+
case "decimal":
|
|
485
|
+
case "float":
|
|
486
|
+
var val = service.parseNumber(data);
|
|
487
|
+
if (String(val) == String(Number(data))) {
|
|
488
|
+
return val;
|
|
489
|
+
}
|
|
490
|
+
return;
|
|
491
|
+
break;
|
|
492
|
+
case "integer":
|
|
493
|
+
var val = service.parseInt(data);
|
|
494
|
+
if (String(val) == String(parseInt(data))) {
|
|
495
|
+
return val;
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
break;
|
|
499
|
+
case "group":
|
|
500
|
+
return data;
|
|
501
|
+
break;
|
|
502
|
+
case "object":
|
|
503
|
+
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
504
|
+
return data;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return;
|
|
508
|
+
break;
|
|
509
|
+
case "string":
|
|
510
|
+
if (service.exists(data)) {
|
|
511
|
+
var stringed = String(data);
|
|
512
|
+
if (stringed == "[object Object]") {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return stringed;
|
|
517
|
+
} else {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// if(!data) {
|
|
522
|
+
// return '';
|
|
523
|
+
// }
|
|
524
|
+
|
|
525
|
+
// if(Array.isArray(data)) {
|
|
526
|
+
// return JSON.stringify(data);
|
|
527
|
+
// }
|
|
528
|
+
|
|
529
|
+
// if(Object.isObject(data)) {
|
|
530
|
+
// return JSON.stringify(data);
|
|
531
|
+
// }
|
|
532
|
+
|
|
533
|
+
// return String(data);
|
|
534
|
+
|
|
535
|
+
// break;
|
|
536
|
+
default:
|
|
537
|
+
return String(data);
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
service.isValidValue = function (value, dataType, strict) {
|
|
543
|
+
var isValue = service.exists(value);
|
|
544
|
+
var valueIsNumber = typeof value == "number";
|
|
545
|
+
|
|
546
|
+
////////////////////////
|
|
547
|
+
|
|
548
|
+
var isValidEntry = false;
|
|
549
|
+
|
|
550
|
+
if (!isValue) {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
////////////////////////
|
|
555
|
+
|
|
556
|
+
switch (dataType) {
|
|
557
|
+
case "url":
|
|
558
|
+
if (strict) {
|
|
559
|
+
isValidEntry =
|
|
560
|
+
value.startsWith("/") ||
|
|
561
|
+
value.startsWith("://") ||
|
|
562
|
+
value.startsWith("http://") ||
|
|
563
|
+
value.startsWith("https://");
|
|
564
|
+
} else {
|
|
565
|
+
isValidEntry = String(value) === service.parseURL(value);
|
|
566
|
+
}
|
|
567
|
+
break;
|
|
568
|
+
case "key":
|
|
569
|
+
isValidEntry = String(value) === service.machineName(value);
|
|
570
|
+
break;
|
|
571
|
+
case "date":
|
|
572
|
+
//If we are being strict
|
|
573
|
+
if (strict) {
|
|
574
|
+
//And the input is not a javascript date object
|
|
575
|
+
if (typeof value != "object" || !(value instanceof Date)) {
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
///////////////////////////////
|
|
581
|
+
var parsed = service.parseDate(value);
|
|
582
|
+
return parsed !== undefined;
|
|
583
|
+
break;
|
|
584
|
+
case "email":
|
|
585
|
+
if (strict) {
|
|
586
|
+
isValidEntry = value === service.parseEmail(value);
|
|
587
|
+
} else {
|
|
588
|
+
isValidEntry =
|
|
589
|
+
String(value).toLowerCase() === service.parseEmail(value);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
break;
|
|
593
|
+
case "number":
|
|
594
|
+
case "decimal":
|
|
595
|
+
case "float":
|
|
596
|
+
if (strict) {
|
|
597
|
+
isValidEntry =
|
|
598
|
+
valueIsNumber && Number(value) === service.parseNumber(value);
|
|
599
|
+
} else {
|
|
600
|
+
isValidEntry = Number(value) === service.parseNumber(value);
|
|
601
|
+
}
|
|
602
|
+
break;
|
|
603
|
+
case "integer":
|
|
604
|
+
if (strict) {
|
|
605
|
+
isValidEntry =
|
|
606
|
+
valueIsNumber && Number(value) === service.parseInt(value);
|
|
607
|
+
} else {
|
|
608
|
+
isValidEntry = Number(value) === service.parseInt(value);
|
|
609
|
+
}
|
|
610
|
+
break;
|
|
611
|
+
case "boolean":
|
|
612
|
+
var parsed = service.parseBoolean(value);
|
|
613
|
+
|
|
614
|
+
//Only accept true booleans
|
|
615
|
+
if (strict) {
|
|
616
|
+
if (value === true || value === false) {
|
|
617
|
+
isValidEntry = value === parsed;
|
|
618
|
+
}
|
|
619
|
+
} else {
|
|
620
|
+
isValidEntry = parsed === true || parsed === false;
|
|
621
|
+
}
|
|
622
|
+
break;
|
|
623
|
+
case "reference":
|
|
624
|
+
if (strict) {
|
|
625
|
+
isValidEntry = String(value) === service.id(value);
|
|
626
|
+
} else {
|
|
627
|
+
isValidEntry = !!service.id(value);
|
|
628
|
+
}
|
|
629
|
+
break;
|
|
630
|
+
case "string":
|
|
631
|
+
var checkString = String(value);
|
|
632
|
+
if (strict) {
|
|
633
|
+
if (typeof value != "string") {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (checkString == "[object Object]") {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
isValidEntry = true;
|
|
643
|
+
break;
|
|
644
|
+
// case 'group':
|
|
645
|
+
// isValidEntry = _isObject(value);
|
|
646
|
+
// break;
|
|
647
|
+
case "object":
|
|
648
|
+
isValidEntry =
|
|
649
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
650
|
+
break;
|
|
651
|
+
case "array":
|
|
652
|
+
isValidEntry = Array.isArray(value);
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
////////////////////////
|
|
657
|
+
|
|
658
|
+
return isValidEntry;
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* A helper function for parsing input as boolean values
|
|
663
|
+
* @alias utils.parseBoolean
|
|
664
|
+
* @param {*} value The input to parse
|
|
665
|
+
* @return {Boolean} the resulting true/false value
|
|
666
|
+
* @example
|
|
667
|
+
*
|
|
668
|
+
* sdk.utils.parseBoolean('true'); // returns true
|
|
669
|
+
* sdk.utils.parseBoolean('y'); // returns true
|
|
670
|
+
* sdk.utils.parseBoolean('YES'); // returns true
|
|
671
|
+
* sdk.utils.parseBoolean('1'); // returns true
|
|
672
|
+
* sdk.utils.parseBoolean('t'); // returns true
|
|
673
|
+
* sdk.utils.parseBoolean(''); // returns false
|
|
674
|
+
* sdk.utils.parseBoolean('0'); // returns false
|
|
675
|
+
* sdk.utils.parseBoolean('n'); // returns false
|
|
676
|
+
* sdk.utils.parseBoolean('no'); // returns false
|
|
677
|
+
* sdk.utils.parseBoolean('f'); // returns false
|
|
678
|
+
* sdk.utils.parseBoolean('null'); // returns false
|
|
679
|
+
*/
|
|
680
|
+
service.parseBoolean = function (value) {
|
|
681
|
+
switch (String(value).toLowerCase()) {
|
|
682
|
+
case "true":
|
|
683
|
+
case "y":
|
|
684
|
+
case "yes":
|
|
685
|
+
case "1":
|
|
686
|
+
case "t":
|
|
687
|
+
value = true;
|
|
688
|
+
break;
|
|
689
|
+
case "false":
|
|
690
|
+
case "n":
|
|
691
|
+
case "no":
|
|
692
|
+
case "0":
|
|
693
|
+
case "f":
|
|
694
|
+
case "undefined":
|
|
695
|
+
case "null":
|
|
696
|
+
case "":
|
|
697
|
+
case "-1":
|
|
698
|
+
value = false;
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return !!value;
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
706
|
+
|
|
707
|
+
service.clone = function (input) {
|
|
708
|
+
return JSON.parse(JSON.stringify(input));
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
712
|
+
|
|
713
|
+
service.getAllFields = function (actualDefinition) {
|
|
714
|
+
const self = this;
|
|
715
|
+
const isProfile =
|
|
716
|
+
actualDefinition.definesType === "profile" ||
|
|
717
|
+
actualDefinition.key === "profile";
|
|
718
|
+
const isFormSubmission = actualDefinition.definesType === "submission";
|
|
719
|
+
var allFields = [...actualDefinition.fields];
|
|
720
|
+
var definedFields = actualDefinition.definedFields || [];
|
|
721
|
+
|
|
722
|
+
if (definedFields.length) {
|
|
723
|
+
if (isFormSubmission) {
|
|
724
|
+
var formDataFields = {
|
|
725
|
+
title: `Form Data`,
|
|
726
|
+
minimum: 1,
|
|
727
|
+
maximum: 1,
|
|
728
|
+
key: "formData",
|
|
729
|
+
asObject: true,
|
|
730
|
+
type: "group",
|
|
731
|
+
fields: definedFields,
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
allFields.push(formDataFields);
|
|
735
|
+
|
|
736
|
+
const cleanedDataFields = definedFields.map(function (field) {
|
|
737
|
+
if (field.type === "reference") {
|
|
738
|
+
field = JSON.parse(JSON.stringify(field));
|
|
739
|
+
delete field.fields;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return field;
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
var dataFields = {
|
|
746
|
+
title: `Data`,
|
|
747
|
+
minimum: 1,
|
|
748
|
+
maximum: 1,
|
|
749
|
+
key: "data",
|
|
750
|
+
asObject: true,
|
|
751
|
+
type: "group",
|
|
752
|
+
fields: cleanedDataFields,
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
allFields.push(dataFields);
|
|
756
|
+
} else {
|
|
757
|
+
var dataFields = {
|
|
758
|
+
title: `${actualDefinition.title}`,
|
|
759
|
+
minimum: 1,
|
|
760
|
+
maximum: 1,
|
|
761
|
+
key: "data",
|
|
762
|
+
asObject: true,
|
|
763
|
+
type: "group",
|
|
764
|
+
fields: definedFields,
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
allFields.push(dataFields);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (isProfile) {
|
|
772
|
+
allFields.push({
|
|
773
|
+
title: "Age",
|
|
774
|
+
key: "_age",
|
|
775
|
+
minimum: 1,
|
|
776
|
+
maximum: 1,
|
|
777
|
+
type: "integer",
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
allFields.push({
|
|
781
|
+
title: "Date of birth",
|
|
782
|
+
key: "_dob",
|
|
783
|
+
minimum: 1,
|
|
784
|
+
maximum: 1,
|
|
785
|
+
type: "date",
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
var mapped = service
|
|
790
|
+
.mapFields(allFields)
|
|
791
|
+
.filter(function (field) {
|
|
792
|
+
var isObject =
|
|
793
|
+
field.type == "group" &&
|
|
794
|
+
field.asObject &&
|
|
795
|
+
field.minimum == 1 &&
|
|
796
|
+
field.maximum == 1;
|
|
797
|
+
return !isObject;
|
|
798
|
+
})
|
|
799
|
+
.map(function (field) {
|
|
800
|
+
field.title =
|
|
801
|
+
field.filterTitle || field.titles.filter(Boolean).join(" › ");
|
|
802
|
+
|
|
803
|
+
return field;
|
|
804
|
+
})
|
|
805
|
+
.sort(function (a, b) {
|
|
806
|
+
return a.title < b.title ? -1 : 1;
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
return mapped;
|
|
810
|
+
};
|
|
811
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
812
|
+
|
|
813
|
+
service.mapFields = function (fields, options) {
|
|
814
|
+
if (!options) {
|
|
815
|
+
options = {};
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
//////////////////////////////
|
|
819
|
+
|
|
820
|
+
var output = [];
|
|
821
|
+
var trail = [];
|
|
822
|
+
var titles = [];
|
|
823
|
+
var currentDepth = 1;
|
|
824
|
+
var depthLimit = options.depth;
|
|
825
|
+
var delimiter = options.arrayDelimeter || "[]";
|
|
826
|
+
|
|
827
|
+
//Loop through each field
|
|
828
|
+
fields.forEach(mapField);
|
|
829
|
+
|
|
830
|
+
//////////////////////////////
|
|
831
|
+
|
|
832
|
+
//Recursively map the fields
|
|
833
|
+
function mapField(field, i) {
|
|
834
|
+
var fieldKey = field.key;
|
|
835
|
+
var isGroup = field.type == "group";
|
|
836
|
+
var singleValue = field.minimum === field.maximum && field.minimum === 1;
|
|
837
|
+
var asObject = field.asObject; // || (isGroup && singleValue);
|
|
838
|
+
var isLayout = isGroup && !asObject;
|
|
839
|
+
|
|
840
|
+
//////////////////////////////////
|
|
841
|
+
|
|
842
|
+
// Whether to clone the field or use the existing reference
|
|
843
|
+
var mapped = options.original ? field : service.clone(field);
|
|
844
|
+
|
|
845
|
+
mapped.trail = trail.slice();
|
|
846
|
+
mapped.trail.push(fieldKey);
|
|
847
|
+
|
|
848
|
+
mapped.path = mapped.trail.join(".");
|
|
849
|
+
mapped.titles = titles.slice();
|
|
850
|
+
mapped.titles.push(field.filterTitle || field.title || "");
|
|
851
|
+
|
|
852
|
+
const isNotLayoutOrIsAllowed = !isLayout || options.includeLayout;
|
|
853
|
+
|
|
854
|
+
//If its an actual element or we've asked to include
|
|
855
|
+
//layout only elements
|
|
856
|
+
if (isNotLayoutOrIsAllowed) {
|
|
857
|
+
//Add it to the mix
|
|
858
|
+
output.push(mapped);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
//////////////////////////////////
|
|
862
|
+
|
|
863
|
+
//Now see if there are child fields and should we go further
|
|
864
|
+
var limitHit = depthLimit && currentDepth >= depthLimit;
|
|
865
|
+
|
|
866
|
+
//If there are child fields for this field
|
|
867
|
+
if (field.fields && field.fields.length) {
|
|
868
|
+
//If it's just a group with no extra key
|
|
869
|
+
if (isLayout) {
|
|
870
|
+
//Loop through fields as if they are at the same depth
|
|
871
|
+
field.fields.forEach(mapField);
|
|
872
|
+
} else {
|
|
873
|
+
//We don't need to traverse any further
|
|
874
|
+
//because we hit the limit
|
|
875
|
+
if (limitHit) {
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
//Move down a level and add to the object
|
|
880
|
+
//Include the key in the path trail
|
|
881
|
+
currentDepth++;
|
|
882
|
+
|
|
883
|
+
let injectKey = fieldKey;
|
|
884
|
+
if (options.includeArrayDelimeter) {
|
|
885
|
+
if (!singleValue) {
|
|
886
|
+
injectKey = `${fieldKey}${delimiter}`;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
trail.push(injectKey);
|
|
890
|
+
titles.push(field.filterTitle || field.title);
|
|
891
|
+
|
|
892
|
+
//Loop through each field
|
|
893
|
+
field.fields.forEach(mapField);
|
|
894
|
+
|
|
895
|
+
//Move back up a level before we go to the next field
|
|
896
|
+
currentDepth--;
|
|
897
|
+
trail.pop();
|
|
898
|
+
titles.pop();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return output;
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* A helpful function that can take a keyed object literal and map it to url query string parameters
|
|
910
|
+
* @alias utils.mapParameters
|
|
911
|
+
* @param {Object} parameters The object you want to transalte
|
|
912
|
+
* @return {String} The query string
|
|
913
|
+
* @example
|
|
914
|
+
* //Returns &this=that&hello=world
|
|
915
|
+
* sdk.utils.mapParameters({"this":"that", "hello":"world"})
|
|
916
|
+
*/
|
|
917
|
+
service.mapParameters = function (parameters) {
|
|
918
|
+
parameters = parameters || {};
|
|
919
|
+
|
|
920
|
+
var array = [];
|
|
921
|
+
|
|
922
|
+
Object.entries(parameters).forEach(function ([key, value]) {
|
|
923
|
+
if (value === undefined || value === null || value == false) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
if (Array.isArray(value)) {
|
|
928
|
+
value.forEach(function (v) {
|
|
929
|
+
array.push(`${key}=${encodeURIComponent(v)}`);
|
|
930
|
+
});
|
|
931
|
+
} else {
|
|
932
|
+
array.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
return array.join("&");
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* A function that will take an integer and a currency string and return a formatted numeric amount rounded to 2 decimal places
|
|
943
|
+
* @alias utils.formatCurrency
|
|
944
|
+
* @param {Integer} value The amount in cents
|
|
945
|
+
* @param {String} currency The currency to format
|
|
946
|
+
* @return {String} The formatted value
|
|
947
|
+
* @example
|
|
948
|
+
*
|
|
949
|
+
* //Returns £10.00
|
|
950
|
+
* sdk.utils.formatCurrency(1000, 'gbp');
|
|
951
|
+
*
|
|
952
|
+
* //Returns $10.00
|
|
953
|
+
* sdk.utils.formatCurrency(1000, 'usd');
|
|
954
|
+
*
|
|
955
|
+
*/
|
|
956
|
+
service.formatCurrency = function (value, currency, decimalPoints) {
|
|
957
|
+
if (!value || isNaN(value)) {
|
|
958
|
+
value = 0;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
decimalPoints = decimalPoints || 2;
|
|
962
|
+
|
|
963
|
+
var currencyPrefix = service.currencySymbol(currency);
|
|
964
|
+
return `${currencyPrefix}${parseFloat(Number(value) / 100).toFixed(decimalPoints)}`;
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* A function that will take an id and return the type key
|
|
969
|
+
* @alias utils.getTypeFromID
|
|
970
|
+
* @param {String} id The id of an object
|
|
971
|
+
* @return {String} The key
|
|
972
|
+
* @example
|
|
973
|
+
*
|
|
974
|
+
* // Returns 'user'
|
|
975
|
+
* sdk.utils.getTypeFromID('52b523f775beea960013f6cd');
|
|
976
|
+
*
|
|
977
|
+
* // Returns 'role'
|
|
978
|
+
* sdk.utils.getTypeFromID('62b59cb572fb4772e7b5fa93');
|
|
979
|
+
*
|
|
980
|
+
*/
|
|
981
|
+
service.getTypeFromID = function (id) {
|
|
982
|
+
id = service.id(id);
|
|
983
|
+
|
|
984
|
+
if (!id) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
const lookup = {
|
|
989
|
+
21: "organisation",
|
|
990
|
+
23: "comment",
|
|
991
|
+
24: "persona",
|
|
992
|
+
25: "audio",
|
|
993
|
+
26: "campaign",
|
|
994
|
+
28: "smartlist",
|
|
995
|
+
29: "cache",
|
|
996
|
+
40: "application",
|
|
997
|
+
41: "action",
|
|
998
|
+
42: "billinginvoice",
|
|
999
|
+
43: "componentsnapshot",
|
|
1000
|
+
44: "diff",
|
|
1001
|
+
45: "email",
|
|
1002
|
+
46: "submission",
|
|
1003
|
+
49: "import",
|
|
1004
|
+
53: "socket",
|
|
1005
|
+
54: "timetrigger",
|
|
1006
|
+
61: "article",
|
|
1007
|
+
63: "component",
|
|
1008
|
+
65: "event",
|
|
1009
|
+
66: "file",
|
|
1010
|
+
67: "tag",
|
|
1011
|
+
69: "image",
|
|
1012
|
+
70: "profile",
|
|
1013
|
+
72: "role",
|
|
1014
|
+
73: "scope",
|
|
1015
|
+
74: "transaction",
|
|
1016
|
+
75: "user",
|
|
1017
|
+
76: "video",
|
|
1018
|
+
77: "workflowcard",
|
|
1019
|
+
78: "variable",
|
|
1020
|
+
"3c": "patoken",
|
|
1021
|
+
"7b": "uatoken",
|
|
1022
|
+
"7d": "urtoken",
|
|
1023
|
+
"2d": "systemtask",
|
|
1024
|
+
"3d": "export",
|
|
1025
|
+
"5f": "systemflag",
|
|
1026
|
+
"2b": "batch",
|
|
1027
|
+
"3a": "log",
|
|
1028
|
+
"2e": "stat",
|
|
1029
|
+
"2f": "unsubscribe",
|
|
1030
|
+
"6b": "intent",
|
|
1031
|
+
"7c": "upload",
|
|
1032
|
+
"2c": "systemtrigger",
|
|
1033
|
+
"6e": "interface",
|
|
1034
|
+
"4e": "interfacesnapshot",
|
|
1035
|
+
"4f": "notification",
|
|
1036
|
+
"2a": "definition",
|
|
1037
|
+
"7e": "definitionsnapshot",
|
|
1038
|
+
"5e": "integration",
|
|
1039
|
+
"4c": "listener",
|
|
1040
|
+
"6d": "topic",
|
|
1041
|
+
"7a": "code",
|
|
1042
|
+
"4d": "paymentmethod",
|
|
1043
|
+
"6c": "sslcertificate",
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
var hexKey = id.slice(8, 10);
|
|
1047
|
+
return lookup[hexKey];
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* A function that will take a currency string and return the symbol
|
|
1052
|
+
* @alias utils.currencySymbol
|
|
1053
|
+
* @param {String} currency The currency
|
|
1054
|
+
* @return {String} The symbol
|
|
1055
|
+
* @example
|
|
1056
|
+
*
|
|
1057
|
+
* //Returns £
|
|
1058
|
+
* sdk.utils.currencySymbol('gbp');
|
|
1059
|
+
*
|
|
1060
|
+
* //Returns $
|
|
1061
|
+
* sdk.utils.currencySymbol('usd');
|
|
1062
|
+
*
|
|
1063
|
+
*/
|
|
1064
|
+
const CURRENCY_SYMBOLS = { gbp: "\u00A3", eur: "\u20AC" };
|
|
1065
|
+
|
|
1066
|
+
service.currencySymbol = function (currency) {
|
|
1067
|
+
return CURRENCY_SYMBOLS[String(currency).toLowerCase()] || "$";
|
|
1068
|
+
};
|
|
1069
|
+
|
|
1070
|
+
const SUPPORTED_CURRENCIES = [
|
|
1071
|
+
{ code: "usd", countries: ["US"] },
|
|
1072
|
+
{ code: "gbp", countries: ["GB", "UK"] },
|
|
1073
|
+
{ code: "cad", countries: ["CA"] },
|
|
1074
|
+
{ code: "aud", countries: ["AU"] },
|
|
1075
|
+
{ code: "nzd", countries: ["NZ"] },
|
|
1076
|
+
{ code: "sgd", countries: ["SG"] },
|
|
1077
|
+
];
|
|
1078
|
+
|
|
1079
|
+
service.getAvailableCurrencies = function (defaultCountryID) {
|
|
1080
|
+
let currencies = SUPPORTED_CURRENCIES.map(({ code, countries }) => ({
|
|
1081
|
+
name: `${code.toUpperCase()} (${service.currencySymbol(code)})`,
|
|
1082
|
+
value: code,
|
|
1083
|
+
countryCode: Object.fromEntries(countries.map((c) => [c, true])),
|
|
1084
|
+
}));
|
|
1085
|
+
|
|
1086
|
+
if (defaultCountryID) {
|
|
1087
|
+
const idx = currencies.findIndex((c) => c.countryCode[defaultCountryID]);
|
|
1088
|
+
if (idx > 0) {
|
|
1089
|
+
const [match] = currencies.splice(idx, 1);
|
|
1090
|
+
currencies.unshift(match);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
return currencies;
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Creates a fast keyed hash object from an array of items
|
|
1101
|
+
* @alias utils.hash
|
|
1102
|
+
* @param {Array} array The array of items to convert into a hash
|
|
1103
|
+
* @param {String} key The key or path to the property on each item to use as the hashed key
|
|
1104
|
+
* @return {Object} A key/value paired object
|
|
1105
|
+
* @example
|
|
1106
|
+
* //Returns { jimbo:{id:'jimbo', title:'Jim Jones'}, {id:'roger', title:'Roger Fellow'} }
|
|
1107
|
+
* sdk.utils.hash([{id:'jimbo', title:'Jim Jones'}, {id:'roger', title:'Roger Fellow'}], 'id');
|
|
1108
|
+
*
|
|
1109
|
+
*/
|
|
1110
|
+
service.hash = function (items, key) {
|
|
1111
|
+
items = !Array.isArray(items) ? [] : items;
|
|
1112
|
+
return items.reduce(function (memo, item) {
|
|
1113
|
+
const k = key ? _get(item, key) : item;
|
|
1114
|
+
memo[k] = item;
|
|
1115
|
+
return memo;
|
|
1116
|
+
}, {});
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
//////////////////////////////////////////////////
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Returns a subset of values in an array that match a provided rule
|
|
1123
|
+
* @alias utils.extractFromArray
|
|
1124
|
+
* @param {Array} array The array you want to extract values from
|
|
1125
|
+
* @param {String} key The path to the child property you want to extract
|
|
1126
|
+
* @param {Boolean} sum Whether to sum the extracted values together in total
|
|
1127
|
+
* @param {Boolean} flatten Whether to flatten nested child arrays
|
|
1128
|
+
* @param {Boolean} unique Whether to only return unique values
|
|
1129
|
+
* @param {Boolean} exclude Whether to exclude null or undefined values
|
|
1130
|
+
* @param {Object} options Pass through extra options for how to extract the values
|
|
1131
|
+
* @return {Array} An array of all values retrieved from the array, unless provided arguments require otherwise
|
|
1132
|
+
* @example
|
|
1133
|
+
* //Returns [12, 45] as all the values
|
|
1134
|
+
* sdk.utils.extractFromArray([{name:'Wendy', age:12}, {name:'Roger', age:45}], 'age');
|
|
1135
|
+
*
|
|
1136
|
+
* //Returns 32
|
|
1137
|
+
* sdk.utils.extractFromArray([{name:'Wendy', age:12}, {name:'Roger', age:20}], 'age', {sum:true});
|
|
1138
|
+
*
|
|
1139
|
+
*/
|
|
1140
|
+
service.extractFromArray = function (
|
|
1141
|
+
array,
|
|
1142
|
+
key,
|
|
1143
|
+
sum,
|
|
1144
|
+
flatten,
|
|
1145
|
+
unique,
|
|
1146
|
+
exclude,
|
|
1147
|
+
options,
|
|
1148
|
+
) {
|
|
1149
|
+
options = options || {};
|
|
1150
|
+
|
|
1151
|
+
if (sum) {
|
|
1152
|
+
options.sum = sum;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
if (flatten) {
|
|
1156
|
+
options.flatten = true;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
if (unique) {
|
|
1160
|
+
options.unique = true;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
if (exclude) {
|
|
1164
|
+
options.excludeNull = true;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/////////////////
|
|
1168
|
+
|
|
1169
|
+
//Filter the array options by a certain value and operator
|
|
1170
|
+
var extractedValues = array.reduce(function (set, entry) {
|
|
1171
|
+
//Get the value from the object
|
|
1172
|
+
var retrievedValue = _get(entry, key);
|
|
1173
|
+
|
|
1174
|
+
var isNull =
|
|
1175
|
+
!retrievedValue && retrievedValue !== false && retrievedValue !== 0;
|
|
1176
|
+
if (options.excludeNull && isNull) {
|
|
1177
|
+
return set;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
set.push(retrievedValue);
|
|
1181
|
+
return set;
|
|
1182
|
+
}, []);
|
|
1183
|
+
|
|
1184
|
+
if (options.flatten) {
|
|
1185
|
+
extractedValues = extractedValues.flat();
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
if (options.unique) {
|
|
1189
|
+
extractedValues = [...new Set(extractedValues)];
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
if (options.sum) {
|
|
1193
|
+
extractedValues = extractedValues.reduce(function (a, b) {
|
|
1194
|
+
return a + b;
|
|
1195
|
+
}, 0);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
return extractedValues;
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1201
|
+
//////////////////////////////////////////////////////
|
|
1202
|
+
|
|
1203
|
+
/**
|
|
1204
|
+
* A function that can return a selection of values that were found in an array that match a specific rule,
|
|
1205
|
+
* This is often used to evaluate expressions within form fields
|
|
1206
|
+
* @alias utils.matchInArray
|
|
1207
|
+
* @param {Array} array The array to check
|
|
1208
|
+
* @param {String} key The javascript dot notation path to extract
|
|
1209
|
+
* @param {String} value The value to compare against
|
|
1210
|
+
* @param {String} comparator The logical operator to use to compare the extracted value with the provided value ('>', '<', '>=', '<=', 'in', '==') Defaults to '==' (Is equal to)
|
|
1211
|
+
* @return {Array} Returns an array of matching values
|
|
1212
|
+
* @example
|
|
1213
|
+
* //Returns [{name:'Michael', age:45}] as that is only item in the array that matches the criteria
|
|
1214
|
+
* sdk.utils.matchInArray([{name:'Wendy', age:12}, {name:'Michael', age:45}], 'age', 45, '>=');
|
|
1215
|
+
*
|
|
1216
|
+
*/
|
|
1217
|
+
service.matchInArray = function (array, key, v, comparator) {
|
|
1218
|
+
//Filter the array options by a certain v and comparator
|
|
1219
|
+
var matches = array.filter(function (entry) {
|
|
1220
|
+
//Get the v from the object
|
|
1221
|
+
var extracted = _get(entry, key);
|
|
1222
|
+
var found;
|
|
1223
|
+
|
|
1224
|
+
switch (comparator) {
|
|
1225
|
+
case "in":
|
|
1226
|
+
found = extracted.includes(v);
|
|
1227
|
+
break;
|
|
1228
|
+
case ">=":
|
|
1229
|
+
found = extracted >= v;
|
|
1230
|
+
break;
|
|
1231
|
+
case "<=":
|
|
1232
|
+
found = extracted <= v;
|
|
1233
|
+
break;
|
|
1234
|
+
case "<":
|
|
1235
|
+
found = extracted < v;
|
|
1236
|
+
break;
|
|
1237
|
+
case ">":
|
|
1238
|
+
found = extracted > v;
|
|
1239
|
+
break;
|
|
1240
|
+
case "==":
|
|
1241
|
+
default:
|
|
1242
|
+
if (v === undefined) {
|
|
1243
|
+
found = extracted;
|
|
1244
|
+
} else {
|
|
1245
|
+
found = extracted == v;
|
|
1246
|
+
}
|
|
1247
|
+
break;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
return found;
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
return matches;
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1256
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1257
|
+
|
|
1258
|
+
/**
|
|
1259
|
+
* A helpful class that can take an array of values and return them as a comma seperated
|
|
1260
|
+
* string, If the values are objects, then a property to use as the string representation can be specified
|
|
1261
|
+
* @alias utils.comma
|
|
1262
|
+
* @param {Array} array The array of values to translate
|
|
1263
|
+
* @param {String} path An optional property key to use for each value
|
|
1264
|
+
* @return {String} The resulting comma seperated string
|
|
1265
|
+
* @example
|
|
1266
|
+
* //Returns 'cat, dog, bird'
|
|
1267
|
+
* sdk.utils.comma(['cat', 'dog', 'bird']);
|
|
1268
|
+
*
|
|
1269
|
+
* //Returns 'cat, dog, bird'
|
|
1270
|
+
* sdk.utils.comma([{title:'cat'}, {title:'dog'}, {title:'bird'}], 'title');
|
|
1271
|
+
*/
|
|
1272
|
+
service.comma = function (array, path, limit) {
|
|
1273
|
+
if (limit) {
|
|
1274
|
+
array = array.slice(0, limit);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
return array
|
|
1278
|
+
.filter(function (item) {
|
|
1279
|
+
return item != null && item !== undefined && item !== "";
|
|
1280
|
+
})
|
|
1281
|
+
.map(function (item) {
|
|
1282
|
+
if (path && path.length) {
|
|
1283
|
+
return _get(item, path);
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
return item;
|
|
1287
|
+
})
|
|
1288
|
+
.join(", ");
|
|
1289
|
+
};
|
|
1290
|
+
|
|
1291
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1292
|
+
|
|
1293
|
+
//Helper function to get an id of an object
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* Returns a specified _id for an object
|
|
1297
|
+
* @alias utils.id
|
|
1298
|
+
* @param {Object} input An object that is or has an _id property
|
|
1299
|
+
* @param {Boolean} asObjectID Whether to convert to a Mongo ObjectId
|
|
1300
|
+
* @return {String} Will return either a string or a Mongo ObjectId
|
|
1301
|
+
*
|
|
1302
|
+
* @example
|
|
1303
|
+
*
|
|
1304
|
+
* //Returns '5cb3d8b3a2219970e6f86927'
|
|
1305
|
+
* sdk.utils.id('5cb3d8b3a2219970e6f86927')
|
|
1306
|
+
*
|
|
1307
|
+
* //Returns true
|
|
1308
|
+
* typeof service.id({_id:'5cb3d8b3a2219970e6f86927', title, ...}) == 'string';
|
|
1309
|
+
|
|
1310
|
+
* //Returns true
|
|
1311
|
+
* typeof service.id({_id:'5cb3d8b3a2219970e6f86927'}, true) == 'object';
|
|
1312
|
+
*/
|
|
1313
|
+
service.id = function (source) {
|
|
1314
|
+
if (!source) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/////////////////////////////////
|
|
1319
|
+
|
|
1320
|
+
var output;
|
|
1321
|
+
|
|
1322
|
+
if (source._id) {
|
|
1323
|
+
output = String(source._id);
|
|
1324
|
+
} else {
|
|
1325
|
+
output = String(source);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
var isValid = service.isValidID(output);
|
|
1329
|
+
if (!isValid) {
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
return output;
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* Cleans and maps an array of objects to an array of IDs
|
|
1340
|
+
* @alias utils.ids
|
|
1341
|
+
* @param {Array} array An array of objects or object ids
|
|
1342
|
+
* @param {Boolean} asObjectID Whether or not to map the ids as Mongo ObjectIds
|
|
1343
|
+
* @return {Array} An array of Ids
|
|
1344
|
+
*
|
|
1345
|
+
* @example
|
|
1346
|
+
* //Returns ['5cb3d8b3a2219970e6f86927', '5cb3d8b3a2219970e6f86927', '5cb3d8b3a2219970e6f86927']
|
|
1347
|
+
* sdk.utils.ids([{_id:'5cb3d8b3a2219970e6f86927'}, {_id:'5cb3d8b3a2219970e6f86927'}, null, '5cb3d8b3a2219970e6f86927'])
|
|
1348
|
+
*/
|
|
1349
|
+
|
|
1350
|
+
service.ids = function (array) {
|
|
1351
|
+
if (!array) {
|
|
1352
|
+
return [];
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
/////////////////////////////////
|
|
1356
|
+
|
|
1357
|
+
var ids = Object.keys(
|
|
1358
|
+
array.reduce(function (set, entry) {
|
|
1359
|
+
if (!entry) {
|
|
1360
|
+
return set;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
var cleaned = service.id(entry);
|
|
1364
|
+
|
|
1365
|
+
if (cleaned) {
|
|
1366
|
+
set[cleaned] = 1;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return set;
|
|
1370
|
+
}, {}),
|
|
1371
|
+
);
|
|
1372
|
+
|
|
1373
|
+
///////////////////////////////
|
|
1374
|
+
|
|
1375
|
+
return ids;
|
|
1376
|
+
};
|
|
1377
|
+
|
|
1378
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1379
|
+
|
|
1380
|
+
service.isValidID = function (input) {
|
|
1381
|
+
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
|
|
1382
|
+
return checkForHexRegExp.test(String(input));
|
|
1383
|
+
};
|
|
1384
|
+
|
|
1385
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Helper function for retrieving a human readable error message from server error response objects
|
|
1389
|
+
* @alias utils.errorMessage
|
|
1390
|
+
* @param {Object} error The error object to translate
|
|
1391
|
+
* @return {String} The resulting human readable error message
|
|
1392
|
+
*/
|
|
1393
|
+
service.errorMessage = function (err) {
|
|
1394
|
+
if (!err) {
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
if (Array.isArray(err)) {
|
|
1399
|
+
err = err[0];
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// Walk through the error object to find the most useful message
|
|
1403
|
+
let message =
|
|
1404
|
+
err?.response?.data?.message ||
|
|
1405
|
+
(typeof err?.response?.data === "string" ? err.response.data : null) ||
|
|
1406
|
+
err?.message ||
|
|
1407
|
+
null;
|
|
1408
|
+
|
|
1409
|
+
if (Array.isArray(message)) {
|
|
1410
|
+
message = message[0];
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
return message || JSON.stringify(err);
|
|
1414
|
+
};
|
|
1415
|
+
|
|
1416
|
+
////////////////////////////////////
|
|
1417
|
+
|
|
1418
|
+
/**
|
|
1419
|
+
* Generates a globally unique ID, helpful for adding unique keys for iterable loops
|
|
1420
|
+
* @alias utils.guid
|
|
1421
|
+
* @return {String} The new globally unique identifier
|
|
1422
|
+
* @example
|
|
1423
|
+
* //Returns 4323a78br-z16h-289j-zwl1-938lda334asd
|
|
1424
|
+
* sdk.utils.guid()
|
|
1425
|
+
*/
|
|
1426
|
+
service.guid = function () {
|
|
1427
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
1428
|
+
return crypto.randomUUID();
|
|
1429
|
+
}
|
|
1430
|
+
// Fallback for environments without crypto.randomUUID
|
|
1431
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
1432
|
+
const r = (Math.random() * 16) | 0;
|
|
1433
|
+
return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
|
|
1434
|
+
});
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
////////////////////////////////////
|
|
1438
|
+
////////////////////////////////////
|
|
1439
|
+
////////////////////////////////////
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* Helper function for cleaning strings to use as database ids
|
|
1443
|
+
* @alias utils.machineName
|
|
1444
|
+
* @param {String} string The string to clean eg. (Awesome Event!)
|
|
1445
|
+
* @return {String} A cleaned and formatted string eg. (awesomeEvent)
|
|
1446
|
+
*/
|
|
1447
|
+
service.machineName = function (string) {
|
|
1448
|
+
if (!string || !string.length) {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
var regexp = /[^a-zA-Z0-9-_]+/g;
|
|
1453
|
+
return String(string)
|
|
1454
|
+
.replace(regexp, " ")
|
|
1455
|
+
.split("_")
|
|
1456
|
+
.map((part) => _camelCase(part))
|
|
1457
|
+
.join("_");
|
|
1458
|
+
};
|
|
1459
|
+
|
|
1460
|
+
/////////////////////////////////////////////
|
|
1461
|
+
/////////////////////////////////////////////
|
|
1462
|
+
/////////////////////////////////////////////
|
|
1463
|
+
|
|
1464
|
+
export default service;
|
|
1465
|
+
|
|
1466
|
+
/////////////////////////////////////////////
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* A lightweight event emitter that can be attached to any service object
|
|
1470
|
+
* to provide pub/sub event capabilities. Can be called with or without `new`.
|
|
1471
|
+
*/
|
|
1472
|
+
export function EventDispatcher() {
|
|
1473
|
+
const handlers = new Map();
|
|
1474
|
+
|
|
1475
|
+
const emitter = {
|
|
1476
|
+
dispatch(event, details) {
|
|
1477
|
+
const fns = handlers.get(event);
|
|
1478
|
+
if (fns) {
|
|
1479
|
+
for (const fn of fns) {
|
|
1480
|
+
fn(details);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
},
|
|
1484
|
+
|
|
1485
|
+
addEventListener(event, callback) {
|
|
1486
|
+
if (typeof callback !== "function") {
|
|
1487
|
+
throw new TypeError(
|
|
1488
|
+
`Expected a function for addEventListener, received ${typeof callback}`,
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
if (!handlers.has(event)) {
|
|
1493
|
+
handlers.set(event, new Set());
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
handlers.get(event).add(callback);
|
|
1497
|
+
},
|
|
1498
|
+
|
|
1499
|
+
removeEventListener(event, callback) {
|
|
1500
|
+
const fns = handlers.get(event);
|
|
1501
|
+
if (fns) {
|
|
1502
|
+
fns.delete(callback);
|
|
1503
|
+
if (fns.size === 0) {
|
|
1504
|
+
handlers.delete(event);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
},
|
|
1508
|
+
|
|
1509
|
+
removeAllListeners() {
|
|
1510
|
+
handlers.clear();
|
|
1511
|
+
},
|
|
1512
|
+
|
|
1513
|
+
bootstrap(target) {
|
|
1514
|
+
if (!target) return;
|
|
1515
|
+
target.dispatch = emitter.dispatch;
|
|
1516
|
+
target.addEventListener = emitter.addEventListener;
|
|
1517
|
+
target.removeEventListener = emitter.removeEventListener;
|
|
1518
|
+
target.removeAllListeners = emitter.removeAllListeners;
|
|
1519
|
+
},
|
|
1520
|
+
};
|
|
1521
|
+
|
|
1522
|
+
return emitter;
|
|
1523
|
+
}
|
|
1524
|
+
</code></pre>
|
|
1525
|
+
</article>
|
|
1526
|
+
</section>
|
|
1527
|
+
|
|
1528
|
+
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
|
|
1533
|
+
</div>
|
|
1534
|
+
|
|
1535
|
+
<br class="clear">
|
|
1536
|
+
|
|
1537
|
+
<footer>
|
|
1538
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Mon Jul 13 2026 18:47:22 GMT+1000 (Australian Eastern Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1539
|
+
</footer>
|
|
1540
|
+
|
|
1541
|
+
<script>prettyPrint();</script>
|
|
1542
|
+
<script src="scripts/polyfill.js"></script>
|
|
1543
|
+
<script src="scripts/linenumber.js"></script>
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
</body>
|
|
1548
|
+
</html>
|