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); }});
}