UNPKG

@qikdev/sdk

Version:

Promise based Javascript SDK

1,468 lines (1,116 loc) 42.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>qik.utils.js - Documentation</title> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <script src="scripts/nav.js" defer></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav > <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#.hashPermissions">hashPermissions</a></li><li data-type='method'><a href="access.html#.isAdministrator">isAdministrator</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#.delete">delete</a></li><li data-type='method'><a href="api.html#.generateEndpointURL">generateEndpointURL</a></li><li data-type='method'><a href="api.html#.get">get</a></li><li data-type='method'><a href="api.html#.patch">patch</a></li><li data-type='method'><a href="api.html#.post">post</a></li><li data-type='method'><a href="api.html#.put">put</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#.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#.activeFilterKeys">activeFilterKeys</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="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></ul> </nav> <div id="main"> <h1 class="page-title">qik.utils.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>import _get from 'lodash/get.js'; import _isDate from 'lodash/isDate.js'; import _startsWith from 'lodash/startsWith.js'; import _isObject from 'lodash/isObject.js'; import _camelCase from 'lodash/camelCase.js'; import axios from 'axios'; import { isBrowser, isNode } from 'browser-or-node'; /////////////////////////////////////////////////////////////////////////////// const service = {}; //////////////////////////////////// const loadedExternalScripts = {} /** * A function that dynamically include an external javascript resource * ensuring that it will only be included once * @alias utils.loadExternalScript * @param {String} url The url of the external script * @return {Promise} A promise that will be resolved once the script has been loaded * @example * * await sdk.utils.loadExternalScript('https://cdn.javascript.com/external/script.js'); */ service.loadExternalScript = function(url) { const promise = new Promise(createNewScript); function createNewScript(resolve, reject) { if (!document) { return reject('document is undefined') } if (loadedExternalScripts[url]) { return resolve(url); } // Avoid duplicate scripts loadedExternalScripts[url] = true; ////////////////////////////////////// var script = document.createElement('script'); script.type = 'text/javascript'; script.async = true; script.onload = function() { console.log('Loaded external script', url); return resolve(url); }; script.src = url; // Inject it into the document's &lt;head> tag document.head.appendChild(script); } return promise; } const loadedExternalStyles = {} /** * A function that dynamically include an external css resource * ensuring that it will only be included once * @alias utils.loadExternalStyle * @param {String} url The url of the external css * @return {Promise} A promise that will be resolved once the css has been loaded * @example * * await sdk.utils.loadExternalStyle('https://cdn.css.com/external/style.css'); */ service.loadExternalStyle = function(url) { const promise = new Promise(createNewScript); function createNewScript(resolve, reject) { if (!document) { return reject('document is undefined') } if (loadedExternalStyles[url]) { return resolve(url); } // Avoid duplicate scripts loadedExternalStyles[url] = true; ////////////////////////////////////// var script = document.createElement('link'); script.setAttribute('rel', 'stylesheet') script.setAttribute('type', 'text/css') script.setAttribute('href', url) script.onload = function() { console.log('Loaded external stylesheet', url); return resolve(url); }; // Inject it into the document's &lt;head> tag document.head.appendChild(script); } return promise; } /////////////////////////////////////////////////////////////////////////////// service.exists = function(value) { var isUndefinedOrNull; //////////////////////// if (Array.isArray(value)) { return true; } //////////////////////// if (value === 0) { return true; } //////////////////////// switch (typeof value) { case 'undefined': case 'null': isUndefinedOrNull = true; break; default: var string = String(value).toLowerCase(); switch (string) { case '': case 'undefined': case 'null': isUndefinedOrNull = true; break; } break; } return !!!isUndefinedOrNull; } ////////////////////////////////// service.parseDate = function(input) { if (!input) { return; } if (_isDate(input)) { return input; } //Attempt to create a date var d = new Date(input); var isValid = d instanceof Date &amp;&amp; !isNaN(d); if (isValid) { return d; } return; } service.parseURL = function(string) { if (!string) { return false; } const relative = _startsWith(string, '/'); if (relative) { return string; } if (_startsWith(string, '://')) { return string; } if (_startsWith(string, 'mailto:')) { return string; } if (_startsWith(string, 'tel:')) { return string; } if (_startsWith(string, 'sms:')) { return string; } ////////////////////////////////// //If someone entered an email by accident var email = service.parseEmail(string); //Convert it to a mailto link if (email &amp;&amp; email === string) { return `mailto:${email}` } ////////////////////////////////// const withHttp = string => !/^https?:\/\//i.test(string) ? `http://${string}` : string; string = withHttp(string); var valid = RegExp('(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&amp;a-z\\d%_.~+=-@]*)?(\\#[-a-z\\d_@]*)?$', 'i').test(string); if (!valid) { return false; } /////////////////////////// return withHttp(string) } /////////////////////////////////////////////// service.parseNumber = function(input, decimalPoints) { if (!input) { return 0; } input = Number(input); if (isNaN(input)) { return 0; } if (decimalPoints) { var str = input.toFixed(decimalPoints); input = service.parseNumber(str); } return input; } service.isValidEmailAddress = function(email) { var tester = /^[-!#$%&amp;'*+\/0-9=?A-Z^_a-z`{|}~](\.?[-!#$%&amp;'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/; if (!email) return false; var emailParts = email.split('@'); if (emailParts.length !== 2) return false var account = emailParts[0]; var address = emailParts[1]; if (account.length > 64) return false else if (address.length > 255) return false var domainParts = address.split('.'); if (domainParts.some(function(part) { return part.length > 63; })) return false; if (!tester.test(email)) return false; return true; } service.parseEmail = function(input) { if (!input) { return false; } var lowercase = String(input).toLowerCase(); var valid = service.isValidEmailAddress(lowercase); if (!valid) { return false; } else { return lowercase; } } ////////////////////////////////// service.parseInt = function(input) { if (!input) { return 0; } input = parseInt(input); if (isNaN(input)) { return 0; } return input; } service.cleanValue = function(data, type, options) { if (!options) { options = {}; } //////////////////////// var noInputValue = service.exists(data); if (options.strict &amp;&amp; noInputValue &amp;&amp; type != 'boolean') { return data; } //////////////////////// switch (type) { case 'reference': return service.id(data, true); break; case 'boolean': return service.parseBoolean(data); break; case 'url': return service.parseURL(data); break; case 'key': return service.machineName(data); break; case 'email': return service.parseEmail(data); break; case 'date': var parsed = service.parseDate(data, options); if (parsed === undefined) { return; } else { return parsed; } break; case 'number': case 'decimal': case 'float': var val = service.parseNumber(data); if (String(val) == String(Number(data))) { return val; } return; break; case 'integer': var val = service.parseInt(data); if (String(val) == String(parseInt(data))) { return val; } return; break; case 'group': return data; break; case 'object': if (_isObject(data) &amp;&amp; !Array.isArray(data)) { return data } return; break; case 'string': if (service.exists(data)) { var stringed = String(data); if (stringed == '[object Object]') { return; } return stringed } else { return; } // if(!data) { // return ''; // } // if(Array.isArray(data)) { // return JSON.stringify(data); // } // if(Object.isObject(data)) { // return JSON.stringify(data); // } // return String(data); // break; default: return String(data) break; } } service.isValidValue = function(value, dataType, strict) { var isValue = service.exists(value); var valueIsNumber = (typeof value == 'number') //////////////////////// var isValidEntry = false; if (!isValue) { return false; } //////////////////////// switch (dataType) { case 'url': if (strict) { isValidEntry = _startsWith(value, '/') || _startsWith(value, '://') || _startsWith(value, 'http://') || _startsWith(value, 'https://'); } else { isValidEntry = String(value) === service.parseURL(value); } break; case 'key': isValidEntry = String(value) === service.machineName(value); break; case 'date': //If we are being strict if (strict) { //And the input is not a javascript date object if (typeof value != 'object' || !_isDate(value)) { return false; } } /////////////////////////////// var parsed = service.parseDate(value); return parsed !== undefined; break; case 'email': if (strict) { isValidEntry = value === service.parseEmail(value); } else { isValidEntry = String(value).toLowerCase() === service.parseEmail(value); } break; case 'number': case 'decimal': case 'float': if (strict) { isValidEntry = valueIsNumber &amp;&amp; (Number(value) === service.parseNumber(value)); } else { isValidEntry = Number(value) === service.parseNumber(value); } break; case 'integer': if (strict) { isValidEntry = valueIsNumber &amp;&amp; (Number(value) === service.parseInt(value)); } else { isValidEntry = Number(value) === service.parseInt(value); } break; case 'boolean': var parsed = service.parseBoolean(value); //Only accept true booleans if (strict) { if (value === true || value === false) { isValidEntry = value === parsed; } } else { isValidEntry = parsed === true || parsed === false; } break; case 'reference': if (strict) { isValidEntry = String(value) === service.id(value); } else { isValidEntry = !!service.id(value); } break; case 'string': var checkString = String(value); if (strict) { if (typeof value != 'string') { return false; } } if (checkString == '[object Object]') { return false; } isValidEntry = true; break; // case 'group': // isValidEntry = _isObject(value); // break; case 'object': isValidEntry = _isObject(value) &amp;&amp; !Array.isArray(value); break; case 'array': isValidEntry = Array.isArray(value); break; } //////////////////////// return isValidEntry } service.parseBoolean = function(value) { switch (String(value).toLowerCase()) { case 'true': case 'y': case 'yes': case '1': case 't': value = true; break; case 'false': case 'n': case 'no': case '0': case 'f': case 'undefined': case 'null': case '': case '-1': value = false; break; } return !!value; } /////////////////////////////////////////////////////////////////////////////// service.clone = function(input) { return JSON.parse(JSON.stringify(input)); } /////////////////////////////////////////////////////////////////////////////// service.mapFields = function(fields, options) { if (!options) { options = {}; } ////////////////////////////// var output = []; var trail = []; var titles = []; var currentDepth = 1; var depthLimit = options.depth; var delimiter = options.arrayDelimeter || '[]'; //Loop through each field fields.forEach(mapField); ////////////////////////////// //Recursively map the fields function mapField(field, i) { var fieldKey = field.key; var isGroup = field.type == 'group'; var singleValue = (field.minimum === field.maximum) &amp;&amp; field.minimum === 1; var asObject = field.asObject; // || (isGroup &amp;&amp; singleValue); var isLayout = isGroup &amp;&amp; !asObject; ////////////////////////////////// // Whether to clone the field or use the existing reference var mapped = options.original ? field : service.clone(field); mapped.trail = trail.slice(); mapped.trail.push(fieldKey) mapped.path = mapped.trail.join('.'); mapped.titles = titles.slice(); mapped.titles.push(field.title || '') const isNotLayoutOrIsAllowed = (!isLayout || options.includeLayout); //If its an actual element or we've asked to include //layout only elements if (isNotLayoutOrIsAllowed) { //Add it to the mix output.push(mapped); } ////////////////////////////////// //Now see if there are child fields and should we go further var limitHit = depthLimit &amp;&amp; (currentDepth >= depthLimit); //If there are child fields for this field if (field.fields &amp;&amp; field.fields.length) { //If it's just a group with no extra key if (isLayout) { //Loop through fields as if they are at the same depth field.fields.forEach(mapField) } else { //We don't need to traverse any further //because we hit the limit if (limitHit) { return; } //Move down a level and add to the object //Include the key in the path trail currentDepth++; let injectKey = fieldKey; if (options.includeArrayDelimeter) { if (!singleValue) { injectKey = `${fieldKey}${delimiter}` } } trail.push(injectKey) titles.push(field.title); //Loop through each field field.fields.forEach(mapField) //Move back up a level before we go to the next field currentDepth--; trail.pop(); titles.pop(); } } } return output; } /////////////////////////////////////////////////////////////////////////////// /** * A helpful function that can take a keyed object literal and map it to url query string parameters * @alias utils.mapParameters * @param {Object} parameters The object you want to transalte * @return {String} The query string * @example * //Returns &amp;this=that&amp;hello=world * sdk.utils.mapParameters({"this":"that", "hello":"world"}) */ service.mapParameters = function(parameters) { parameters = parameters || {} var array = []; Object.entries(parameters) .forEach(function([key, value]) { if (value === undefined || value === null || value == false) { return; } if (Array.isArray(value)) { value.forEach(function(v) { array.push(`${key}=${encodeURIComponent(v)}`); }) } else { array.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } }) return array.join('&amp;'); } /////////////////////////////////////////////////////////////////////////////// /** * A function that will take an integer and a currency string and return a formatted numeric amount rounded to 2 decimal places * @alias utils.formatCurrency * @param {Integer} value The amount in cents * @param {String} currency The currency to format * @return {String} The formatted value * @example * * //Returns £10.00 * sdk.utils.formatCurrency(1000, 'gbp'); * * //Returns $10.00 * sdk.utils.formatCurrency(1000, 'usd'); * */ service.formatCurrency = function(value, currency) { if (!value || isNaN(value)) { value = 0; } var currencyPrefix = service.currencySymbol(currency); return `${currencyPrefix}${parseFloat(parseInt(value) / 100).toFixed(2)}`; } /** * A function that will take an id and return the type key * @alias utils.getTypeFromID * @param {String} id The id of an object * @return {String} The key * @example * * // Returns 'user' * sdk.utils.getTypeFromID('52b523f775beea960013f6cd'); * * // Returns 'role' * sdk.utils.getTypeFromID('62b59cb572fb4772e7b5fa93'); * */ service.getTypeFromID = function(id) { id = service.id(id); if (!id) { return; } const lookup = { "21": "organisation", "23": "comment", "24": "persona", "25": "audio", "26": "campaign", "28": "smartlist", "29": "cache", "40": "application", "41": "action", "42": "billinginvoice", "43": "componentsnapshot", "44": "diff", "45": "email", "46": "submission", "49": "import", "53": "socket", "54": "timetrigger", "61": "article", "63": "component", "65": "event", "66": "file", "67": "tag", "69": "image", "70": "profile", "72": "role", "73": "scope", "74": "transaction", "75": "user", "76": "video", "77": "workflowcard", "78": "variable", "3c": "patoken", "7b": "uatoken", "7d": "urtoken", "2d": "systemtask", "3d": "export", "5f": "systemflag", "2b": "batch", "3a": "log", "2e": "stat", "2f": "unsubscribe", "6b": "intent", "7c": "upload", "2c": "systemtrigger", "6e": "interface", "4e": "interfacesnapshot", "4f": "notification", "2a": "definition", "7e": "definitionsnapshot", "5e": "integration", "4c": "listener", "6d": "topic", "7a": "code", "4d": "paymentmethod", "6c": "sslcertificate" } var hexKey = id.slice(8, 10); return lookup[hexKey]; } /** * A function that will take a currency string and return the symbol * @alias utils.currencySymbol * @param {String} currency The currency * @return {String} The symbol * @example * * //Returns £ * sdk.utils.currencySymbol('gbp'); * * //Returns $ * sdk.utils.currencySymbol('usd'); * */ service.currencySymbol = function(currency) { //Ensure lowercase currency currency = String(currency).toLowerCase(); switch (String(currency).toLowerCase()) { case 'gbp': return '£'; break; case 'eur': return '€'; break; default: return '$'; break; } } service.getAvailableCurrencies = function(DefaultCountryID) { var array = []; array.push({ name: `USD (${service.currencySymbol("usd")})`, value: "usd", countryCode: { 'US': true }, }); array.push({ name: `GBP (${service.currencySymbol("gbp")})`, value: "gbp", countryCode: { 'GB': true, 'UK': true }, }); array.push({ name: `CAD (${service.currencySymbol("cad")})`, value: "cad", countryCode: { 'CA': true }, }); array.push({ name: `AUD (${service.currencySymbol("aud")})`, value: "aud", countryCode: { 'AU': true }, }); array.push({ name: `NZD (${service.currencySymbol("nzd")})`, value: "nzd", countryCode: { 'NZ': true }, }); array.push({ name: `SGD (${service.currencySymbol("sgd")})`, value: "sgd", countryCode: { 'SG': true }, }); if (DefaultCountryID) { var findMatch = array.findIndex(function(currency) { return currency.countryCode[DefaultCountryID]; }) const moveArrayItem = (array, fromIndex, toIndex) => { const arr = [...array]; arr.splice(toIndex, 0, ...arr.splice(fromIndex, 1)); return arr; } if (findMatch != -1) { array = moveArrayItem(array, findMatch, 0) } } return array; } /////////////////////////////////////////////////////////////////////////////// /** * Creates a fast keyed hash object from an array of items * @alias utils.hash * @param {Array} array The array of items to convert into a hash * @param {String} key The key or path to the property on each item to use as the hashed key * @return {Object} A key/value paired object * @example * //Returns { jimbo:{id:'jimbo', title:'Jim Jones'}, {id:'roger', title:'Roger Fellow'} } * sdk.utils.hash([{id:'jimbo', title:'Jim Jones'}, {id:'roger', title:'Roger Fellow'}], 'id'); * */ service.hash = function(items, key) { items = !Array.isArray(items) ? [] : items; return items.reduce(function(memo, item) { const k = _get(item, key); memo[k] = item; return memo; }, {}); } ////////////////////////////////////////////////// /** * Returns a subset of values in an array that match a provided rule * @alias utils.extractFromArray * @param {Array} array The array you want to extract values from * @param {String} key The path to the child property you want to extract * @param {Boolean} sum Whether to sum the extracted values together in total * @param {Boolean} flatten Whether to flatten nested child arrays * @param {Boolean} unique Whether to only return unique values * @param {Boolean} exclude Whether to exclude null or undefined values * @param {Object} options Pass through extra options for how to extract the values * @return {Array} An array of all values retrieved from the array, unless provided arguments require otherwise * @example * //Returns [12, 45] as all the values * sdk.utils.extractFromArray([{name:'Wendy', age:12}, {name:'Roger', age:45}], 'age'); * * //Returns 32 * sdk.utils.extractFromArray([{name:'Wendy', age:12}, {name:'Roger', age:20}], 'age', {sum:true}); * */ service.extractFromArray = function(array, key, sum, flatten, unique, exclude, options) { options = options || {} if (sum) { options.sum = sum; } if (flatten) { options.flatten = true; } if (unique) { options.unique = true; } if (exclude) { options.excludeNull = true; } ///////////////// //Filter the array options by a certain value and operator var extractedValues = array.reduce(function(set, entry) { //Get the value from the object var retrievedValue = _get(entry, key); var isNull = (!retrievedValue &amp;&amp; (retrievedValue !== false &amp;&amp; retrievedValue !== 0)); if (options.excludeNull &amp;&amp; isNull) { return set; } set.push(retrievedValue); return set; }, []) if (options.flatten) { extractedValues = _.flatten(extractedValues); } if (options.unique) { extractedValues = _.uniq(extractedValues); } if (options.sum) { extractedValues = extractedValues.reduce(function(a, b) { return a + b; }, 0); } return extractedValues; } ////////////////////////////////////////////////////// /** * A function that can return a selection of values that were found in an array that match a specific rule, * This is often used to evaluate expressions within form fields * @alias utils.matchInArray * @param {Array} array The array to check * @param {String} key The javascript dot notation path to extract * @param {String} value The value to compare against * @param {String} comparator The logical operator to use to compare the extracted value with the provided value ('>', '&lt;', '>=', '&lt;=', 'in', '==') Defaults to '==' (Is equal to) * @return {Array} Returns an array of matching values * @example * //Returns [{name:'Michael', age:45}] as that is only item in the array that matches the criteria * sdk.utils.matchInArray([{name:'Wendy', age:12}, {name:'Michael', age:45}], 'age', 45, '>='); * */ service.matchInArray = function(array, key, v, comparator) { //Filter the array options by a certain v and comparator var matches = array.filter(function(entry) { //Get the v from the object var extracted = _get(entry, key); var found; switch (comparator) { case 'in': found = extracted.includes(v); break; case '>=': found = (extracted >= v); break; case '&lt;=': found = (extracted &lt;= v); break; case '&lt;': found = (extracted &lt; v); break; case '>': found = (extracted > v); break; case '==': default: if (v === undefined) { found = extracted; } else { found = (extracted == v); } break; } return found; }) return matches; } /////////////////////////////////////////////////////////////////////////////// /** * A helpful class that can take an array of values and return them as a comma seperated * string, If the values are objects, then a property to use as the string representation can be specified * @alias utils.comma * @param {Array} array The array of values to translate * @param {String} path An optional property key to use for each value * @return {String} The resulting comma seperated string * @example * //Returns 'cat, dog, bird' * sdk.utils.comma(['cat', 'dog', 'bird']); * * //Returns 'cat, dog, bird' * sdk.utils.comma([{title:'cat'}, {title:'dog'}, {title:'bird'}], 'title'); */ service.comma = function(array, path, limit) { if (limit) { array = array.slice(0, limit); } return _.chain(array) .compact() .map(function(item) { if (path &amp;&amp; path.length) { return _get(item, path); } return item; }) .value() .join(', '); } /////////////////////////////////////////////////////////////////////////////// //Helper function to get an id of an object /** * Returns a specified _id for an object * @alias utils.id * @param {Object} input An object that is or has an _id property * @param {Boolean} asObjectID Whether to convert to a Mongo ObjectId * @return {String} Will return either a string or a Mongo ObjectId * * @example * * //Returns '5cb3d8b3a2219970e6f86927' * sdk.utils.id('5cb3d8b3a2219970e6f86927') * * //Returns true * typeof service.id({_id:'5cb3d8b3a2219970e6f86927', title, ...}) == 'string'; * //Returns true * typeof service.id({_id:'5cb3d8b3a2219970e6f86927'}, true) == 'object'; */ service.id = function(source) { if (!source) { return; } ///////////////////////////////// var output; if (source._id) { output = String(source._id); } else { output = String(source); } var isValid = service.isValidID(output); if (!isValid) { return; } return output; } /////////////////////////////////////////////////////////////////////////////// /** * Cleans and maps an array of objects to an array of IDs * @alias utils.ids * @param {Array} array An array of objects or object ids * @param {Boolean} asObjectID Whether or not to map the ids as Mongo ObjectIds * @return {Array} An array of Ids * * @example * //Returns ['5cb3d8b3a2219970e6f86927', '5cb3d8b3a2219970e6f86927', '5cb3d8b3a2219970e6f86927'] * sdk.utils.ids([{_id:'5cb3d8b3a2219970e6f86927'}, {_id:'5cb3d8b3a2219970e6f86927'}, null, '5cb3d8b3a2219970e6f86927']) */ service.ids = function(array) { if (!array) { return []; } ///////////////////////////////// var ids = Object.keys(array.reduce(function(set, entry) { if (!entry) { return set; } var cleaned = service.id(entry) if (cleaned) { set[cleaned] = 1; } return set; }, {})) /////////////////////////////// return ids; } /////////////////////////////////////////////////////////////////////////////// service.isValidID = function(input) { var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$") return checkForHexRegExp.test(String(input)); } /////////////////////////////////////////////////////////////////////////////// /** * Helper function for retrieving a human readable error message from server error response objects * @alias utils.errorMessage * @param {Object} error The error object to translate * @return {String} The resulting human readable error message */ service.errorMessage = function(err) { if (!err) { return; } if (Array.isArray(err)) { err = err[0]; } //////////////////////////////////// var candidates = [ 'response.data.message', 'response.data', 'message', ] var message; candidates.forEach(function(path) { if (message) { return; } var m = _get(err, path); if (m) { message = m; } }) if (Array.isArray(message)) { message = message[0]; } //////////////////////////////////// message = message || JSON.stringify(err); //////////////////////////////////// return message; } //////////////////////////////////// /** * Generates a globally unique ID, helpful for adding unique keys for iterable loops * @alias utils.guid * @return {String} The new globally unique identifier * @example * //Returns 4323a78br-z16h-289j-zwl1-938lda334asd * sdk.utils.guid() */ service.guid = function() { var u = (new Date()).getTime().toString(16) + Math.random().toString(16).substring(2) + "0".repeat(16); return u.substr(0, 8) + '-' + u.substr(8, 4) + '-4000-8' + u.substr(12, 3) + '-' + u.substr(15, 12); } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// /** * Helper function for cleaning strings to use as database ids * @alias utils.machineName * @param {String} string The string to clean eg. (Awesome Event!) * @return {String} A cleaned and formatted string eg. (awesomeEvent) */ service.machineName = function(string) { if (!string || !string.length) { return; } var regexp = /[^a-zA-Z0-9-_]+/g; var cleaned = String(string).replace(regexp, ' '); return _camelCase(cleaned); } ///////////////////////////////////////////// ///////////////////////////////////////////// ///////////////////////////////////////////// export default service; ///////////////////////////////////////////// //Export the event dispatcher export function EventDispatcher() { var listeners = {}; ///////////////////////////////////////////// var dispatcher = {} ///////////////////////////////////////////// //Remove all listeners dispatcher.removeAllListeners = function() { listeners = {}; } ///////////////////////////////////////////// dispatcher.dispatch = function(event, details) { if (listeners[event]) { //For each listener listeners[event].forEach(function(callback) { return callback(details); }); } } ///////////////////////////////////////////// dispatcher.addEventListener = function(event, callback) { if (!listeners[event]) { listeners[event] = []; } const type = typeof callback; if (type !== 'function') { throw new Error(`addEventListener() requires a function but ${type} was added`); } else { if (listeners[event].indexOf(callback) == -1) { //Add to the listeners listeners[event].push(callback) } else { //A //lready listening } } } ///////////////////////////////////////////// dispatcher.removeEventListener = function(event, callback) { if (!listeners[event]) { listeners[event] = []; } //Get the index of the listener var index = listeners[event].indexOf(callback); if (index != -1) { //Remove from the listeners listeners[event].splice(index, 1); } } ///////////////////////////////////////////// //Wrap the event listener functionality dispatcher.bootstrap = function(service) { if (!service) { // console.log('No service to bootstrap to') return; } service.dispatch = dispatcher.dispatch; service.addEventListener = dispatcher.addEventListener; service.removeEventListener = dispatcher.removeEventListener; service.removeAllListeners = dispatcher.removeAllListeners; } ///////////////////////////////////////////// return dispatcher; }</code></pre> </article> </section> </div> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Thu Sep 28 2023 07:24:39 GMT+1000 (Australian Eastern Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script>prettyPrint();</script> <script src="scripts/polyfill.js"></script> <script src="scripts/linenumber.js"></script> </body> </html>