app = angular.module('kim', ['chart.js','ngSanitize', 'angular-bind-html-compile']); getCurrentMsalIdentity = function(_tenantId, _clientId, _then) { try { var msalInstance = new msal.PublicClientApplication({ auth: { clientId: _clientId, authority: "https://login.microsoftonline.com/" + _tenantId, redirectUri: "https://" + window.location.host + "/api/msal_auth" } }); const silentRequest = { scopes: ["openid", "profile", "email"], }; msalInstance.ssoSilent(silentRequest).then((response) => { _then(response.account); }); } catch (e) { return null; } } performAzureLogin = function(_http, _tenantId, _clientId, _then) { try { // Initialize MSAL instance var msalInstance = new msal.PublicClientApplication({ auth: { clientId: _clientId, authority: "https://login.microsoftonline.com/" + _tenantId, redirectUri: "https://" + window.location.host + "/api/msal_auth" } }); var loginRequest = { scopes: ["openid", "profile"] }; msalInstance.loginPopup(loginRequest).then((loginResponse) => { var account = msalInstance.getAllAccounts()[0]; // Send the ID token to the server for validation _http.post('/api/msal_auth', { id_token: loginResponse.idToken }).then((response) => { if (_then) { _then(response); } }); }).catch((error) => { _then({ data: { auth: false, error: error + "" } }); }); } catch (error) { _then({ data: { auth: false, error: error + "" } }); } } app.config(['$locationProvider', function($locationProvider) { $locationProvider.html5Mode({ enabled: true, requireBase: false, rewriteLinks: false }); }]); app.controller("scanner_input", function($scope, $http, $location, $rootScope, $sce, $interval, $timeout) { }); Number.prototype.toCurrency = function() { return (this ?? 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }; Date.prototype.copyTimeComponent = function(_source, _includeMs) { this.setHours(_source ? _source.getHours() : 0); this.setMinutes(_source ? _source.getMinutes() : 0); this.setSeconds(_source ? _source.getSeconds() : 0); this.setMilliseconds(_source && _includeMs ? _source.getMilliseconds() : 0); }; Date.prototype.sameDateAs = function(_compare) { return _compare && _compare.getFullYear() == this.getFullYear() && _compare.getMonth() == this.getMonth() && _compare.getDate() == this.getDate(); }; String.prototype.replaceAll = function(_old, _new) { if (_old === _new) { return this; } var temp = this; var index = temp.indexOf(_old); while (index != -1) { temp = temp.replace(_old, _new); index = temp.indexOf(_old); } return temp; }; generateRecordActionSelections = function(_scope, _http, _sce, _recordActionIds) { var selections = { }; _recordActionIds.forEach((id, idi) => { var action = _scope.$root.allRecordActions[id]; if (id == "6791b6136732d8705b66b39a") { selections[id + "_" + idi] = { seperator: true }; } else if (action) { selections[id] = { label: action.label, class: action.label_class || "secondary", icon: (action.icon_resource ? "/" + action.icon_resource : null), subIcon: (action.sub_icon_resource ? "/" + action.sub_icon_resource : null), onClick: function(args) { (new Function("record", "modelName", "field", "query", "scope", "http", "sce", action.script))( _scope.directiveScope.record ?? args.target.record, _scope.directiveScope.modelName, args.target.field, _scope.directiveScope.query, _scope, _http, _sce ) }, data: { html: action.html, supportingJs: ` try { // Set js vars var scope = $scope.$parent.$parent.$parent; var http = $http; var sce = $sce; var modelName = scope.directiveScope.modelName; var modelData = scope.directiveScope.modelData; var layoutRecord = scope.directiveScope.layoutRecord; var query = scope.directiveScope.query; // Set html vars $scope.scope = scope; scope.http = http; scope.sce = sce; scope.modelName = modelName; scope.modelData = modelData; scope.layoutRecord = layoutRecord; scope.query = query; ` + (action.supporting_js ?? ``) + ` } catch (e) { console.log("Failed to evaluate record action ` + action._id + ` (` + action.name + `), " + e); }` }, dynamicDisplay: (action.visible_script ?? "").length > 0 ? function(args) { return (new Function("record", "modelName", "field", "scope", "http", action.visible_script))( _scope.directiveScope.record ?? args.target.record, _scope.directiveScope.modelName, args.target.field, _scope, _http ) } : null, dynamicLabel: (action.label_script ?? "").length > 0 ? function(args) { return (new Function("record", "modelName", "field", "scope", "http", action.label_script))( _scope.directiveScope.record ?? args.target.record, _scope.directiveScope.modelName, args.target.field, _scope, _http ) } : null, dynamicIcon: (action.icon_script ?? "").length > 0 ? function(args) { return (new Function("record", "modelName", "field", "scope", "http", action.icon_script))( _scope.directiveScope.record ?? args.target.record, _scope.directiveScope.modelName, args.target.field, _scope, _http ) } : null, dynamicSubIcon: (action.sub_icon_script ?? "").length > 0 ? function(args) { return (new Function("record", "modelName", "field", "scope", "http", action.sub_icon_script))( _scope.directiveScope.record ?? args.target.record, _scope.directiveScope.modelName, args.target.field, _scope, _http ) } : null } } }); return selections; } Object.assignDeep = function(_target, _source, _field) { if (!_field) { _target = _target ?? {}; _source = _source ?? {}; //Raw object Object.keys(_source).forEach((p) => { Object.assignDeep(_target, _source, p); }); } else { //Specific property var newValue = _source[_field]; var oldValue = _target[_field]; if (newValue == null) { _target[_field] = newValue; } else if (Array.isArray(newValue)) { _target[_field] = _target[_field] ?? Array(newValue.length).fill(null); newValue.forEach((v, i) => { Object.assignDeep(_target[_field], _source[_field], i); }); } else if (typeof(newValue) == "object") { Object.keys(newValue).forEach((p) => { _target[_field] = _target[_field] ?? {}; Object.assignDeep(_target[_field], _source[_field], p); }); } else { _target[_field] = newValue; } } } // function constructGlobalSearch($scope, _modelName, _searchTerm) { //Ensure modifications are performed in server version var query = {}; var modelData = $scope.$root.models[_modelName]; if (_searchTerm.length < 1) { return query; } else { var validTranslators = ["61fc3fefd59d630c7ac95f0c", "6020673d59d74a2d584dfd5e"]; var allFields = cloneObject(modelData.fields); /* Object.keys($scope.$root.models).forEach((m) => { var model = $scope.$root.models[m]; if (model.parent == _modelName) { Object.keys(model.fields).forEach((f) => { allFields[f] = cloneObject(model.fields[f]); }); } }); */ query = { $or: Object.keys(allFields).filter((f) => { var field = allFields[f]; return f != "_type" && (modelData.parent != "remote_record" || field.remote_queryable) && (["string", "enumerator", "number", "reference"].includes(field.type)) && field.queryable && !$scope.$root.globalFields[f]; }).map((f) => { var c = {}; if (allFields[f].type == "number") { if (!isNaN(_searchTerm)) { //Number c[f] = parseFloat(_searchTerm); return c; } } else if (allFields[f].type == "reference") { if (isValidIdString(_searchTerm)) { //Reference c[f] = _searchTerm; return c; } } else if(["string", "enumerator"].includes(allFields[f].type)) { //String c = { $or: [{}] }; c.$or[0][f] = _searchTerm; if (!(allFields[f].virtual_translation && allFields[f].selections)) { c.$or.push({}); c.$or[1][f] = { $regex: ".*" + _searchTerm + ".*", $options: 'i' }; if (_searchTerm.length > 2) { //Base64 for(var i = 0; i < 4; i++) { var padding = ""; for(var p = 0; p < i; p++) { padding += " "; } var modQueryBase64 = btoa(padding + _searchTerm).slice(i).split("=").join(""); modQueryBase64 = modQueryBase64.slice(0, modQueryBase64.length - 2); if (modQueryBase64.length > 0) { c.$or.push({}); c.$or[c.$or.length - 1][f] = { $regex: ".*" + modQueryBase64 + ".*" }; } } } } return c; } }).filter((c) => { return !!c; }) }; if (isValidIdString(_searchTerm)) { query.$or.push({ _id: _searchTerm }); } } return query; } function formatDollarAmount(_usd) { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(_usd); } function replaceRelationFields(_scope, _string) { var replacedFields = []; var toProcess = _string || ""; do { var match = toProcess.match(/\<[^\>]*\>/); if (match) { toProcess = toProcess.replace(/\<[^\>]*\>/, (field) => { //Arguments, raw var arguments = field.replace("<","").replace(">","").split(","); var fieldName = arguments.shift(); if (fieldName.startsWith("$scope.")) { var f = new Function("$scope", "return " + fieldName); return JSON.stringify(f(_scope)); } else { replacedFields.push(fieldName); return arguments.includes("raw") ? _scope.record[fieldName] : JSON.stringify(_scope.record[fieldName] || null); } }); } } while(match); return { output: toProcess, replacedFields: replacedFields.distinct() }; } function scrollToElement(_id, _parentId) { var scrollTo = document.getElementById(_id); if (_parentId) { document.getElementById(_parentId).scrollTop = scrollTo.offsetTop; } else { scrollTo.scrollIntoView(true); } } function elementIsVisible(_id) { try { return $("#" + _id).is(":visible"); } catch (e) { return false; } } String.prototype.truncate = function(_length, _append) { _append = _append || "..."; if (!this) { return this; } return this.length > _length ? (this.substring(0, _length) + _append) : this; }; function arrayToObjectBy(_array, _property, _removeField) { var obj = {}; _array.forEach((i) => { if (typeof(i) != "object") { throw "Cannot convert array to object by " + _property + ", invalid value"; } var key = i[_property].toString(); if (Object.keys(obj).includes(key)) { throw "Cannot convert array to object by " + _property + ", duplicate key value"; } obj[key] = i; if (_removeField) { delete obj[key][_property]; } }); return obj; } function getServerTime(_http, _then) { _http.get("/api/current_time", { withCredentials: true }).then((json) => { postProcessJSON(json); if (_then) { _then(json.data); } }); } Array.prototype.distinct = function() { return this == null ? null : Array.from(new Set(this)); } Array.prototype.last = function() { if (!this || !Array.isArray(this)) { return null; } return this[this.length - 1]; }; Array.prototype.sum = function() { if (!this || !Array.isArray(this)) { return 0; } return this.reduce((sum, v) => { return sum + v; }, 0); }; Array.prototype.indexOfCondition = function(_method) { for(var i = 0; i < this.length; i++) { if (_method(this[i])) { return i; } } return -1; }; function parseDateDifference(_diff) { var diff = Math.abs((_diff == null ? 0 : _diff) / 1000); var output = { days: 0, hours: 0, minutes: 0, seconds: 0 } while(diff >= 86400) { output.days++; diff-=86400; } while(diff >= 3600) { output.hours++; diff-=3600; } while(diff >= 60) { output.minutes++; diff-=60; } while(diff >= 1) { output.seconds++; diff-=1; } return output; } function getFormattedTime(_ms) { var comps = parseDateDifference((_ms || 0)); var ds = ""; if (comps.days > 0) { ds += comps.days + " day "; } if (comps.hours > 0) { ds += comps.hours + " hrs "; } if (comps.minutes > 0) { ds += comps.minutes + " min "; } if (comps.seconds > 0) { ds += comps.seconds + " sec"; } return ds; } function collectAllRoles($scope, $http, _parentRolesOrRole, _then) { var allRoles = []; if (_parentRolesOrRole) { var parents = (Array.isArray(_parentRolesOrRole) ? _parentRolesOrRole : [_parentRolesOrRole]).distinct(); //Add parent roles allRoles.push(...parents); //Get parent roles info retrieveRecords($scope, $http, "role", { query: { _id: { $in: parents }}}, (parentsResponse) => { //Get child roles of the parent roles var children = parentsResponse.records.map((r) => { return r.contained_roles; }).flat().distinct(); if (children.length > 0) { collectAllRoles($scope, $http, children, (childRoles) => { allRoles.push(...childRoles); if (_then) { _then(allRoles.distinct()); } }); } else if (_then) { _then(allRoles.distinct()); } }); } } function getDefaultControls($scope, _model, _field) { var field = $scope.$root.models[_model].fields[_field]; return { singular_read: field ? $scope.$root.controls[field.selections ? "6023e2298989745e0939f791" : $scope.$root.kimConfig["default_singular_" + field.type + "_read_control" ]] : null, singular_write: field ? $scope.$root.controls[field.selections ? "602338ec175393570a177213" : $scope.$root.kimConfig["default_singular_" + field.type + "_write_control"]] : null, plural_read: field ? $scope.$root.controls[field.selections ? "6282388314e1110384d78db9" : $scope.$root.kimConfig["default_plural_" + field.type + "_read_control" ]] : null, plural_write: field ? $scope.$root.controls[field.selections ? "62857728fa1f641bafe08e20" : $scope.$root.kimConfig["default_plural_" + field.type + "_write_control"]] : null }; } function getScopeFromHTMLElement(_htmlElement) { return angular.element(_htmlElement).scope(); } function getSortedObject(_object, _function) { if (!_object) { return _object; } return Object.keys(_object).map((k) => { return { key: k, value: _object[k] }}).sort(_function); } function msToDuration(_ms, _maxIntervals) { var neg = _ms < 0; _ms = Math.abs(_ms); var comps = []; var intervals = [86400000, 3600000, 60000, 1000].reverse().slice(0, _maxIntervals || 9999).reverse(); for(var interval of intervals) { var iCount = 0; while(_ms >= interval) { iCount++; _ms -= interval; } comps.push(iCount.toString().padStart(2, "0")); } return (neg ? "-" : "+") + comps.join(":"); } function downloadLink(_link, _name) { let link = document.createElement("a"); link.download = _name || ""; link.href = _link; link.click(); } function formatDataSize(_bytes) { _bytes = _bytes || 0; var thresholds = { TB: 1099511627776, GB: 1073741824, MB: 1048576, KB: 1024, B: 1 }; for(var t of Object.keys(thresholds)) { if (_bytes >= thresholds[t]) { return Math.round(_bytes / thresholds[t]) + " " + t; } } } function safeApply(_scope) { var phase = _scope.$root.$$phase; if(phase == '$apply' || phase == '$digest') { } else { _scope.$apply(); } }; String.prototype.toCamelCase = function() { return this.toLowerCase().replaceAll("_", " ").split(" ").map((w, i) => { return (i == 0 ? w.charAt(0) : w.charAt(0).toUpperCase()) + w.slice(1) }).join(""); } String.prototype.toTitleCase = function() { return this.toLowerCase().replaceAll("_", " ").split(" ").map((w) => { return w.charAt(0).toUpperCase() + w.slice(1) }).join(" "); } Array.prototype.removeIndex = function(_index) { if (_index > -1 && _index < this.length) { this.splice(_index, 1); } return this; } function groupByProperty(_array, _field) { if (!_array || !_field) { return {}; } var groups = {}; for(var i of _array) { var normalizedValue = i[_field] == undefined ? null : i[_field]; if (!groups[normalizedValue]) { groups[normalizedValue] = []; } groups[normalizedValue].push(i); } return groups; } function postProcessJSON(_json) { //Since custom JSON parsing isnt yet available in HttpClient we'll need to do some client side casting to the correct types if (_json == null) { return null; } Object.keys(_json).forEach((p) => { if (_json[p] != null) { if (isValidDateString(_json[p])){ _json[p] = new Date(_json[p]); } else if (typeof(_json[p]) == "object"){ postProcessJSON(_json[p]); } } }); }; function isValidDateString(_string) { var dateRegex = new RegExp("^\\d{4}-\\d{2}-\\d{2}T\\d{2}\:\\d{2}\:\\d{2}.\\d{3}Z$", "g"); return _string && dateRegex.test(_string); } function isValidIdString(_string) { //Ensure modifications are performed in server version var idRegEx = new RegExp("[0-9a-f]{24}", "g"); return _string && idRegEx.test(_string); } function getKimConfig($scope, $http, _then) { $http.get("/api/config", { withCredentials: true }).then( function(json){ postProcessJSON(json.data); _then(json.data ? json.data : {}); }, function(json) { postProcessJSON(json.data); _then(json.data ? json.data : {}); } ); } function getModelById($scope, _id) { return Object.values($scope.$root.models).find((model) => { return model._id == _id; }); } function getCurrentRoles($scope, $http, _then){ $http.get("/api/roles/current", { withCredentials: true }).then( function(json){ postProcessJSON(json.data); _then(json.data ? json.data : []); }, function(json) { postProcessJSON(json.data); _then(json.data ? json.data : {}); } ); } function countRecords($scope, $http, _model, _query, _then) { retrieveRecords($scope, $http, _model, { query: _query, select: ["_id"], limit: 1 }, (response) => { _then(response.total_count); }); } function retrieveRecords($scope, $http, _model, _options, _then) { _options = _options ? _options : {}; _options.query = _options.query ? _options.query : {}; var queryString = JSON.stringify(_options.query); //Check for large query if (queryString.length > 1000) { //Create a large_request_query record to avoid URL length issues insertRecord($scope, $http, "large_request_query", { query: queryString }, (response) => { if (response.success) { $http.get("/api/data/" + _model + "?query=" + "&sort=" + JSON.stringify(_options.sort || {}) + "&skip=" + JSON.stringify(_options.skip || 0) + "&limit=" + JSON.stringify(_options.limit || 999999) + "&populate=" + JSON.stringify(_options.populate || []) + (_options.select ? ("&select=" + JSON.stringify(_options.select)) : "") + "&large=" + response.record._id, { withCredentials: true }).then( function(json) { postProcessJSON(json.data); _then(json.data); }, function(json) { postProcessJSON(json.data); _then(json.data ? json.data : {}); } ); } else { _then({ total_count: 0, records: [], error: { errors: [{ message: "Failed to commit large request record"}]} }); } }); } else { $http.get("/api/data/" + _model + "?query=" + queryString + "&sort=" + JSON.stringify(_options.sort || {}) + "&skip=" + JSON.stringify(_options.skip || 0) + "&limit=" + JSON.stringify(_options.limit || 999999) + (_options.select ? ("&select=" + JSON.stringify(_options.select)) : "") + "&populate=" + JSON.stringify(_options.populate || []) + (_options.noCache ? ("&noCache=" + (new Date()).toString()) : ""), { withCredentials: true, }).then(function(json) { postProcessJSON(json.data); _then(json.data); }, function(json) { postProcessJSON(json.data); _then(json.data); } ); } } function mergeObjects(_target, _source) { if (_target == null || _source == null) { return; } if (typeof(_source) == "object") { //Check each source field Object.keys(_source).forEach((p) => { var sourceValue = _source[p]; if (typeof(sourceValue) == "object") { //Source value is an object, recursively process mergeObjects(_target[p], sourceValue); } else { //Source value is a primitive, convert the target propoerty to an objectif neccessary, then assign source value _target[p] = typeof(_target[p]) == "object" ? _target[p] : {}; _target[p] = sourceValue; } }); } } //Deprecated function getRecords($scope, $http, _model, _query, _populate, _sort, _skip, _limit, _then){ console.log("Deprecated function used: getRecords"); retrieveRecords($scope, $http, _model, { query: _query, populate: _populate, sort: _sort, skip: _skip, limit: _limit }, _then); } function retrieveRecord($scope, $http, _model, _options, _then){ _options.limit = 1; retrieveRecords($scope, $http, _model, _options, (data) => { _then((data.error || data.records.length < 1) ? null : data.records[0]); }); } function getRecord($scope, $http, _model, _query, _populate, _then){ console.log("Deprecated function used: getRecord"); retrieveRecord($scope, $http, _model, { query: _query, populate: _populate }, _then); } function getCurrentUser($scope, $http, _then){ $http.get("/api/auth/current", { withCredentials: true }).then( function(json) { _then(json.data); }, function(json) { postProcessJSON(json.data); _then(json.data ? json.data : {}); } ); } function logOut($scope, $http, _then) { $http.post("/api/auth/logout", null, { withCredentials: true }).then(function(json){ if (_then) {_then(json.data);} }); } function logIn($scope, $http, _username, _password, _then) { $http.post("/api/auth/", { username: _username, password: _password }).then(function(json){ if (_then) {_then(json.data);} }); } function deleteRecord($scope, $http, _model, _id, _then){ //Note: query is in body for DELETEs $http.delete("/api/data/" + _model + "/" + _id, { withCredentials: true }).then(function(json){ if (_then) {_then(json.data);} }); } function deleteRecords($scope, $http, _model, _query, _then){ postProcessJSON(_query); //Note: query is in body for DELETEs $http.delete("/api/data/" + _model + "?query=" + JSON.stringify(_query), { withCredentials: true }).then(function(json){ if (_then) {_then(json.data);} }); } function updateRecord($scope, $http, _model, _id, _data, _then){ $http.post("/api/data/" + _model + "?_id=" + _id, _data, { withCredentials: true }).then(function(json){ if (_then) {_then(json.data);} },function(json){ if (_then) {_then(json.data);} }); } function updateRecords($scope, $http, _model, _idsAndData, _onFinalUpdate, _onEachUpdate, _originalCount) { if (_idsAndData && typeof(_idsAndData) == "object" && Object.keys(_idsAndData).length > 0 ) { _originalCount = _originalCount == null ? Object.keys(_idsAndData).length : _originalCount; var id = Object.keys(_idsAndData)[0]; $http.post("/api/data/" + _model + "?_id=" + id, _idsAndData[id], { withCredentials: true }).then( function(json) { var newIdsAndData = cloneObject(_idsAndData); delete newIdsAndData[id]; if (_onEachUpdate) { // Execute _onEachUpdate, if the result is FALSE, cancel the updates var callbackResult = _onEachUpdate({ id: id, progress: 1 - (Object.keys(newIdsAndData).length / _originalCount) }); if (callbackResult === false) { if (_onFinalUpdate) { _onFinalUpdate(); } return; } } updateRecords($scope, $http, _model, newIdsAndData, _onFinalUpdate, _onEachUpdate, _originalCount); }, function(error) { var newIdsAndData = cloneObject(_idsAndData); delete newIdsAndData[id]; if (_onEachUpdate) { _onEachUpdate({ id: id, progress: 1 - (Object.keys(newIdsAndData).length / _originalCount), error: error.data }); } updateRecords($scope, $http, _model, newIdsAndData, _onFinalUpdate, _onEachUpdate, _originalCount); }); } else if (_onFinalUpdate) { _onFinalUpdate(); } } function insertRecord($scope, $http, _model, _data, _then){ $http.post("/api/data/" + _model + "?insert=true", _data, { withCredentials: true }).then(function(json){ if (_then) { _then(json.data); } }); } function getModels($scope, $http, _then){ $http.get("/api/models", { withCredentials: true }).then( function(json){ _then(json.data); }, function(json) { _then(json.data ? json.data : {}); }); } function getApps($scope, $http, _then){ $http.get("/api/apps", { withCredentials: true }).then( function(json){ _then(json.data); }, function(json) { _then(json.data ? json.data : {}); }); } function getURIParameters() { if (!window.location.href.includes("?")) { return {};} var params = {}; window.location.href.split("?")[1].split("&").forEach(function(param) { var paramQuals = param.split("="); params[paramQuals[0]] = paramQuals[1]; }); return params; } function getPageName() { if (!window.location.href.includes("/")) {return null;} var comps = window.location.href.split("/"); return comps[comps.length - 1].split("?")[0]; } function mapObjectValues(_object, _func) { if (_object == null) { return null; } var m = {}; Object.keys(_object).forEach((k) => { m[k] = _func([_object.k], k); }); return m; } function searchFullScope(_scope, _field) { var scope = _scope; while (scope.$parent){ if (scope.hasOwnProperty(_field)) { return scope[_field]; } scope = scope.$parent; } return null; }; function cloneObject(_obj) { return _obj == null ? null : JSON.parse(JSON.stringify(_obj)); } function createUniqueTag() { return btoa(Math.random().toString().replace(".","")).split("=")[0]; } function compressString(_string) { return uint8ArrayToUtf16String(pako.deflateRaw(_string));; } function decompressString(_compressed) { return new TextDecoder().decode(pako.inflateRaw(utf16StringToUint8Array(_compressed))); } function clearBaseData() { window.sessionStorage.clear(); } function uint8ArrayToUtf16String(_uint8Array) { var paddedLength = _uint8Array.length % 2 !== 0 ? _uint8Array.length + 1 : _uint8Array.length; var dataView = new DataView(_uint8Array.buffer); var utf16String = ""; for (var i = 0; i < paddedLength; i += 2) { try { utf16String += String.fromCharCode(dataView.getUint16(i, true)); } catch (e) { utf16String += String.fromCharCode(dataView.getUint8(i, true)); } } return utf16String; } function utf16StringToUint8Array(_utf16String) { var uint8Array = new Uint8Array(_utf16String.length * 2); var dataView = new DataView(uint8Array.buffer); for (var i = 0; i < _utf16String.length; i++) { dataView.setUint16(i * 2, _utf16String.charCodeAt(i), true); } return uint8Array; } function loadBaseData(_scope, _http, _then) { _scope.$root.recordCache = _scope.$root.recordCache || {}; var cachedBaseData = window.sessionStorage.getItem("baseData"); if (cachedBaseData) { //Exists, is it valid? cachedBaseData = JSON.parse(decompressString(cachedBaseData)); postProcessJSON(cachedBaseData); if (cachedBaseData.roles) { //Valid _scope.$root.serverTimeOffset = cachedBaseData.serverTime - (new Date()); _scope.$root.kimConfig = cachedBaseData.kimConfig; _scope.$root.currentUser = cachedBaseData.user; _scope.$root.layouts = cachedBaseData.layouts; _scope.$root.models = cachedBaseData.models; _scope.$root.segments = cachedBaseData.segments; _scope.$root.roles = cachedBaseData.roles; _scope.$root.controls = cachedBaseData.controls; _scope.$root.menu_containers = cachedBaseData.menu_containers; _scope.$root.client_ip = cachedBaseData.client_ip; _scope.$root.client_ci = cachedBaseData.client_ci; _scope.$root.globalFields = cachedBaseData.globalFields; _scope.$root.globalControls = cachedBaseData.global_controls; _scope.$root.fieldTypes = cachedBaseData.field_types; _scope.$root.allRecordActions = cachedBaseData.all_record_actions; _scope.$root.formRecordActions = cachedBaseData.form_record_actions; _scope.$root.listRecordActions = cachedBaseData.list_record_actions; _scope.$root.listHeaderActions = cachedBaseData.list_header_actions; _scope.$root.colors = cachedBaseData.colors; _scope.$root.sysadmin = _scope.$root.roles.some((r) => { return r._id == "5d44d5351747c171a2639ca3"; }); linkControlsToLayouts(_scope.$root); _scope.$root.baseDataLoaded = true; if (_then) { _then(); } return ; } } //Missing or invalid, reload _scope.$root.baseDataLoaded = false; _http.get("/basedata", { withCredentials: true }).then( function(json) { postProcessJSON(json.data); window.sessionStorage.setItem("baseData", compressString(JSON.stringify(json.data))); loadBaseData(_scope, _http, _then); }, function(json) { _then(json.data ? json.data : {}); } ); } function linkControlsToLayouts(_root) { for(var layout of _root.layouts) { for(var field of layout.fields) { field.control = typeof(field.control) == 'object' ? field.control : _root.controls[field.control]; } } } function loadCurrentUser(_scope, _http, _then) { getCurrentUser(_scope, _http, (user) => { _scope.$root.currentUser = user; if (_then) { _then(); } }); } function loadAllLayouts(_scope, _http, _then) { if (_scope.$root.layouts) { if (_then) { _then(); } } else { getRecords(_scope, _http, "layout", {}, ["fields.control"], {}, null, null, (response) => { _scope.$root.layouts = response.records; if (_then) { _then(); } }); } } function loadAllModels(_scope, _http, _then) { if (_scope.$root.models) { if (_then) { _then(); } } else { getModels(_scope, _http, (models) => { _scope.$root.models = models; if (_then) { _then(); } }); } } function loadCurrentRoles(_scope, _http, _then) { if (_scope.$root.roles) { if (_then) { _then(); } } else { getCurrentRoles(_scope, _http, (roles) => { _scope.$root.roles = roles; if (_then) { _then(); } }); } } function claimEnumeration(_scope, _http, _id, _then) { _http.get("/api/enumerator/" + _id + "?claim=true", { withCredentials: true }).then( function(json){ _then(json.data); }, function(json) { _then(json.data ? json.data : {}); }); } function waitForElement(_id, _then) { setTimeout(() => { var element = document.getElementById(_id); if (element) { _then(element); } else { waitForElement(_id, _then); } }, 100); } function encodeHtml(_html) { return btoa(unescape(encodeURIComponent(_html))); } function decodeHtml(_encoded) { try { return decodeURIComponent(escape(atob(_encoded))); } catch(e) { return null; } } function getDistinct(_array) { var o = []; (_array || []).forEach((e) => { if (!o.includes(e)) { o.push(e); } }); return o; } function setUrl(_location, _url) { _location.url(_url).replace(); } function getRootScope(_scope) { if (_scope.$id == 0) { return _scope; } else if (_scope.$parent) { return getRootScope(_scope.$parent); } else if (_scope.$root) { return _scope.$root; } else { return null; } } function hashCode(_string) { let hash = 0; for (let i = 0, len = _string.length; i < len; i++) { let chr = _string.charCodeAt(i); hash = (hash << 5) - hash + chr; hash |= 0; } return hash; } function retrievePropertyCollisions(_objectArray, _evaluationFields, _then) { _objectArray = _objectArray ?? []; _evaluationFields = _evaluationFields ?? []; var collisions = {}; _evaluationFields.forEach((evaluationField) => { var fieldValueGroups = groupByProperty(_objectArray, evaluationField); Object.keys(fieldValueGroups).forEach((groupValue) => { if (fieldValueGroups[groupValue].length > 1) { collisions[evaluationField] = collisions[evaluationField] ?? {}; collisions[evaluationField][groupValue] = fieldValueGroups[groupValue]; } }); }); if (_then) { _then(collisions); } } function retrieveRecordCollisions(_scope, _http, _model, _query, _evaluationFields, _then) { _evaluationFields = _evaluationFields ?? Object.keys(_scope.$root.models[_model].fields).filter((f) => { var fieldModel = _scope.$root.models[_model].fields[f]; return f != "_id"; }); retrieveRecords(_scope, _http, _model, { query: _query ?? {}, select: _evaluationFields }, (response) => { retrievePropertyCollisions(response.records, _evaluationFields, _then); }); } function formatPhoneNumber(_raw) { _raw = (_raw ?? "").replace(/\D/g, "").padStart(15, " "); var line = _raw.substring(11, 15); var office = _raw.substring(8, 11); var area = _raw.substring(5, 8); var country = _raw.substring(0, 5).trim(); return (country + " " + area + " " + office + "-" + line).trim(); } function formatJsonToHtml(_object) { if (_object == null) { return `null`; } else if (Array.isArray(_object)) { if (_object.length == 0) { return `[]`; } return `[
` + _object.map((e) => { return formatJsonToHtml(e); }).join(`,
`) + `
]`; } else if (typeof(_object) == "object" && !_object.getDate) { if (Object.keys(_object).length == 0) { return `{}`; } return `{
` + Object.keys(_object).map((k) => { return `"` + k + `": ` + formatJsonToHtml(_object[k]); }).join(`,
`) + `
}`; } else if (typeof(_object) == "string") { return `` + JSON.stringify(_object).split(`<`).join(`<`).split(`>`).join(`>`) + ``; } else if (typeof(_object) == "boolean") { return `` + JSON.stringify(_object) + ``; } else { return `` + JSON.stringify(_object) + ``; } } function cancelTask($scope, $http, _executionId, _then) { updateRecord($scope, $http, "task_execution", _executionId, { state: "cancel_pending" }, _then); } function executeTask($scope, $http, _task, _options, _init, _complete) { _options = _options || {}; _options.parameters = _options.parameters || {}; _options.data = _options.data || {}; _options.type = _options.type || "task_execution"; var data = _options.data; data.task = _task, data.parameters = _options.parameters; insertRecord($scope, $http, _options.type, data, (response) => { if (_init) { _init(response.record); } if (_complete) { var cbInterval = setInterval(() => { retrieveRecord($scope, $http, _options.type, { query: { _id: response.record._id }}, (execution) => { if (["succeeded", "failed", "cancelled"].includes(execution.state)) { clearInterval(cbInterval); return _complete(execution); } }); }, 2500); } }); } function sendEmail($scope, $http, _to, _subject, _body, _html, _attachments, _replyTo, _then){ $http.post("/api/email", { to: _to, subject: _subject, body: _body, html: _html, attachments: _attachments, replyTo: _replyTo }, { withCredentials: true }).then(() => { if (_then) { _then(true); }}); } function sendTemplatedEmail($scope, $http, _to, _templateName, _record, _attachments, _replyTo, _then) { $http.post("/api/templatedEmail", { to: _to, template: _templateName, record: _record, attachments: _attachments, replyTo: _replyTo }, { withCredentials: true }).then(() => { if (_then) { _then(true); }}); }