window.nuDialog = new nuCreateDialog('');
window.nuFORM = new nuFormObject();
window.nuRESPONSIVE = new nuResponseForm();
window.nuOnLoad = null;
window.nuBeforeSaveGlobal = null;
window.nuLoadBrowseGlobal = null;
window.nuLoadEditGlobal = null;
window.nuOnLookupPopulatedGlobal = null;
window.nuOnTabSelectedGlobal = null;
window.nuOnPopupOpenedGlobal = null;
window.nuOnOptionsListLoadedGlobal = null;
window.nuOnDisableGlobal = null;
window.nuOnLabelPositionCustom = null;
window.top.document.nuHideMessage = true;
window.nuDragID = 1000;
window.nuLastForm = '';
window.nuLastFocus = null;
window.nuNEW = '';
window.nuColor = '';
window.nuImage = '';
window.nuSESSION = '';
window.nuDRAGLINEVSTART = '';
window.nuDRAGLINEVID = '';
window.nuLASTRECORD = '';
window.nuMESSAGES = [];
window.nuSAVED = true;
window.nuImages = [];
window.nuOPENER = [];
window.nuSUBFORMROW = [];
window.nuSUBFORMJSON = [];
window.nuSCHEMA = [];
window.nuLANGUAGE = [];
window.nuFIELD = [];
window.nuHASH = [];
window.nuBEFORE = [];
window.nuAFTER = [];
window.nuBROWSERESIZE = {
x_position: 0,
mouse_down: false,
moving_element: '',
pointer: '',
current_cell_width: 0,
next_cell_left: 0,
array_current_cell_left: '',
last_moved_element: ''
};
String.prototype.nuEndsWith = function (substr, ignoreCase = false) {
if (!ignoreCase) return this.endsWith(substr);
return this.toLowerCase().endsWith(substr.toLowerCase());
};
String.prototype.nuStartsWith = function (substr, ignoreCase = false) {
if (!ignoreCase) return this.startsWith(substr);
return this.toLowerCase().startsWith(substr.toLowerCase());
};
String.prototype.nuReplaceAll = function (str1, str2, ignore) {
return this.replace(new RegExp(str1.replace(/([\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, function (c) { return "\\" + c; }), "g" + (ignore ? "i" : "")), str2);
};
String.prototype.nuStringToArray = function (separator = ',', trim = true) {
const result = this.split(separator);
return trim ? result.map(item => item.trim()) : result;
}
String.prototype.nuLeftTrim = function () {
return this.replace(/^\s+/, "");
}
String.prototype.nuRightTrim = function () {
return this.replace(/\s+$/, "");
}
String.prototype.containsAny = String.prototype.containsAny || function (arr) {
for (var i = 0; i < arr.length; i++) {
if (this.indexOf(arr[i]) > -1) {
return true;
}
}
return false;
};
String.prototype.nuReplaceNonBreakingSpaces = function (replaceWith = ' ') {
return this.replace(/\xA0/g, replaceWith)
}
String.prototype.nuCapitalise = function () {
return this.charAt(0).toUpperCase() + this.slice(1);
}
String.prototype.nuToTitleCase = function () {
return this.toLowerCase().replace(/^(\w)|\s(\w)/g, (grp) => grp.toUpperCase());
}
String.prototype.nuJustNumbers = function () {
return this.replace(/[^0-9]/g, '');
}
String.prototype.nuWithoutNumbers = function () {
return this.replace(/\d+/g, '');
}
String.prototype.nuStripBoundaryTags = function (openTag, closeTag) {
let result = this.trim().toString();
if (result.startsWith(openTag)) {
result = result.slice(openTag.length);
}
if (result.endsWith(closeTag)) {
result = result.slice(0, -closeTag.length);
}
return result;
};
String.prototype.nuInsertString = function (index, string) {
if (index > 0) {
return this.substring(0, index) + string + this.substring(index);
}
return string + this;
};
String.prototype.nuIsEmpty = function () {
return (this === null || this.length === 0);
}
String.prototype.nuHasHTMLTag = function (tag) {
const escapeTagName = (name) => name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let regex;
if (Array.isArray(tag)) {
const escapedTags = tag.map(escapeTagName);
const regexString = `(${escapedTags.join('|')})\\b[^>]*>`;
regex = new RegExp(regexString, 'i');
} else {
const escapedTagName = escapeTagName(tag);
regex = new RegExp(`(${escapedTagName})\\b[^>]*>`, 'i');
}
const match = this.match(regex);
return match ? match[1] : false;
};
Date.prototype.nuWithoutTime = function () {
let d = new Date(this);
d.setHours(0, 0, 0, 0);
return d;
}
Date.prototype.nuAddDays = function (days) {
let date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
}
String.prototype.nuFormat = function () {
var args;
args = arguments;
if (args.length === 1 && args[0] !== null && typeof args[0] === 'object') {
args = args[0];
}
return this.replace(/{([^}]*)}/g, function (match, key) {
return (typeof args[key] !== "undefined" ? args[key] : match);
});
};
$.fn.nuOnEnterKey = function (fn, preventDefault = false) {
return this.each(function () {
$(this).on('keydown', e => {
if (e.key === 'Enter') {
if (preventDefault) {
e.preventDefault();
}
fn.call(this, e);
}
});
});
};
$.fn.nuFocusWithoutScrolling = function () {
let element = $(this)[0];
if (element === undefined) {
return;
}
let x = element.scrollX, y = element.scrollY;
this.attr('inputmode', 'none');
nuSetFocus(this);
this.removeAttr('inputmode');
element.scrollTo(x, y);
return this;
};
jQuery.fn.extend({
nuEnable: function (enable) {
return this.each(function () {
nuEnable(this.id, enable);
});
},
nuReadonly: function (readonly) {
return this.each(function () {
nuReadonly(this.id, readonly);
});
},
nuDisable: function () {
return this.each(function () {
nuDisable(this.id);
});
},
nuShow: function (visible, openTab) {
return this.each(function () {
nuShow(this.id, visible, openTab);
});
},
nuHide: function () {
return this.each(function () {
nuHide(this.id);
});
},
nuRemove: function () {
return this.each(function () {
nuRemove(this.id);
});
},
nuSelectRemoveEmpty: function (setIndex) {
return this.each(function () {
nuSelectRemoveEmpty(this.id, setIndex);
});
},
nuGetValue: function (method) {
return nuGetValue(this.attr('id'), method);
},
nuSetValue: function (v, method, change) {
return this.each(function () {
return nuSetValue(this.id, v, method, change);
});
},
nuGetText: function () {
return nuGetValue(this.attr('id'), 'text');
},
nuSetText: function (v) {
return this.each(function () {
return nuSetValue(this.id, v, 'text');
});
},
nuGetHTML: function () {
return nuGetValue(this.attr('id'), 'html');
},
nuTranslate: function (method) {
return this.each(function () {
nuSetValue(this.id, nuTranslate(nuGetValue(this.id, method)), method);
});
},
nuRemoveFormatting: function () {
return nuFORM.removeFormatting($(this).val(), $(this).attr('data-nu-format'));
},
nuIsVisible: function () {
return nuIsVisible(this.attr('id'));
},
nuIsHidden: function () {
return nuIsHidden(this.attr('id'));
},
nuIsDisabled: function () {
return nuIsDisabled(this.attr('id'));
},
nuIsEnabled: function () {
return nuIsEnabled(this.attr('id'));
},
nuSetFocus: function () {
return nuSetFocus(this.attr('id'));
},
nuSetPlaceholder: function (placeholder, translate) {
return this.each(function () {
return nuSetPlaceholder(this.id, placeholder, translate);
});
},
nuSetLabelText: function (str, translate) {
return this.each(function () {
nuSetLabelText(this.id, str, translate);
});
},
nuTogglePassword: function (show) {
return this.each(function () {
let $input = $(this);
let type = $input.attr('type') === 'password' ? 'text' : 'password';
if (show !== undefined) {
type = show ? 'text' : 'password';
}
$input.attr('type', type);
});
}
});
function nuSelectInParentContext(selector, context = 'document') {
if (window === window.parent) {
return $([]);
}
try {
const parentContext = context === 'body'
? window.parent.document.body
: window.parent.document;
return $(selector, parentContext);
} catch (e) {
if (e.name === 'SecurityError') {
console.warn('Cross-origin access denied');
} else {
console.warn('Error accessing parent context:', e.message);
}
return $([]);
}
}
function nuSelectInParentDocument(selector) {
return nuSelectInParentContext(selector, 'document');
}
function nuSelectInParentBody(selector) {
return nuSelectInParentContext(selector, 'body');
}
function nujQueryObj(id) {
if (typeof id === 'string') {
return $('#' + id);
} else if (id instanceof HTMLElement) {
return $(id);
} else if (id instanceof jQuery) {
return id;
} else {
return jQuery([]);
}
}
function nuElement(id) {
if (typeof id === 'string') {
if (/^[#.\[]/.test(id)) {
return Array.from(document.querySelectorAll(id));
}
let el = document.getElementById(id);
return el ? [el] : [];
} else if (id instanceof HTMLElement) {
return [id];
} else if (id instanceof NodeList || Array.isArray(id)) {
return Array.from(id);
} else {
return [];
}
}
function nuPad4(id, pad = '0') {
return nuPad(id, 4, pad);
}
function nuPad3(id, pad = '0') {
return nuPad(id, 3, pad);
}
function nuPad2(id, pad = '0') {
return nuPad(id, 2, pad);
}
function nuPad(id, length, pad = '0') {
return id.toString().padStart(length, pad);
}
function nuGlobalAccess() {
return window.global_access;
}
function nuTriggerEvent(element, event = 'change') {
if (element instanceof jQuery) {
element.trigger(event);
} else {
let ev = new Event(event);
element.dispatchEvent(ev);
}
}
function nuOpener(t, f, r, filter, parameters) {
nuSetSuffix();
this.id = String(Date.now()) + String(window.nuSuffix);
this.form_id = f;
this.record_id = r;
this.type = t;
this.filter = nuDefine(filter);
this.parameters = nuDefine(parameters);
}
function nuOpenerAppend(t, k) {
window.nuOPENER[window.nuOPENER.length - 1][t] = k;
}
function nuGetOpenerById(pOPENER, pid) {
for (let i = 0; i < pOPENER.length; i++) {
if (pOPENER[i].id == pid) {
return pOPENER[i];
}
}
return;
}
function nuRemoveOpenerById(o, pid) {
for (let i = 0; i < o.length; i++) {
if (o[i].id == pid) {
o.splice(i, 1);
}
}
}
function nuGetBreadcrumb(bc) {
if (window.nuOnBeforeGetBreadcrumb) {
if (nuOnBeforeGetBreadcrumb(bc) == false) return;
}
nuSaveScrollPositions();
const breadCrumbIndex = arguments.length === 0 ? nuFORM.breadcrumbs.length - 1 : bc;
window.nuTimesSaved = -1;
if (nuFORM.edited && nuFORM.getCurrent().form_type != 'launch') {
if (!confirm(nuTranslate('Leave this form without saving?'))) {
return;
}
}
window.nuFORM.removeAfter(breadCrumbIndex);
const current = window.nuFORM.getCurrent();
if (current === undefined) {
nuGetNuDragDialogIframes().remove();
} else {
nuForm(current.form_id, current.record_id, current.filter, current.search, 1);
}
}
function nuOpenPreviousBreadcrumb(offset = 1) {
const modal = parent.$('#nuModal');
if (modal.length) {
nuClosePopup();
return true;
}
const bcIndex = Math.max(2, offset + 1);
const bcLength = window.nuFORM.breadcrumbs.length;
if (bcLength > 1) {
nuGetBreadcrumb(bcLength - bcIndex);
return true;
}
return false;
}
function nuDisplayError(errorObj) {
if (!errorObj.errors || errorObj.errors.length === 0) {
return false;
}
const messageDiv = nuMessage(errorObj.errors);
window.nuOnMessage?.(messageDiv, errorObj.errors);
return !errorObj.after_event;
}
function nuFormatAjaxErrorRemoveJSON(responseText) {
if (typeof responseText !== 'string') {
return responseText
}
const normalized = responseText.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
const lines = normalized.split('\n');
if (lines.length >= 3) {
const third = lines[2].trim();
const idPayloadRe = /^\{\s*"id"\s*:\s*".*?"\s*\}$/;
if (idPayloadRe.test(third)) {
return lines.slice(0, 2).join('\n');
}
}
return responseText;
}
function nuFormatAjaxErrorMessage(jqXHR, exception) {
const errorMessages = {
0: nuTranslate('Not connected. Please verify your network connection.'),
403: [`
${nuTranslate('Access Forbidden.')}
`, jqXHR.responseText],
404: nuTranslate('The requested page was not found.') + ' [404]',
500: nuTranslate('Internal Server Error.') + ' [500]',
parsererror: nuTranslate('Requested JSON parse failed.'),
timeout: nuTranslate('Time out error.'),
abort: nuTranslate('Ajax request aborted.'),
};
const errorMessage = errorMessages[jqXHR.status] || errorMessages[exception] ||
[`${nuTranslate('Uncaught Error.')}
`, nuFormatAjaxErrorRemoveJSON(jqXHR.responseText)]
return errorMessage;
}
function nuLogin(loginTopRow, nuconfigNuWelcomeBodyInnerHTML, logonMode = 'normal', onlySsoExcept = {}, lastUser = "") {
var HTML = String(nuconfigNuWelcomeBodyInnerHTML).trim();
loginTopRow = String(loginTopRow).trim();
window.nuSESSION = '';
window.nuFORM = new nuFormObject();
$('body').html('');
var defaulTopRow = `

|
`;
var topRow = loginTopRow == '' ? defaulTopRow : loginTopRow;
var h1 = `
`;
if (logonMode == 'normal') {
var h = h1 + h3normal + h4;
} else if (logonMode == 'sso') {
var h = h1 + h2sso + h4;
} else if (logonMode == 'both') {
if (lastUser in onlySsoExcept || "allusers" in onlySsoExcept) { // Selectively show username/password login option if found in 'onlySsoExcept' dictionary - most users only see SSO button
var h = h1 + h2sso + h3normal + h4;
} else {
var h = h1 + h2sso + h4;
}
} else { // Original/normal mode
var h = h1 + h3normal + h4;
}
var H = HTML == '' ? h : HTML;
var e = document.createElement('div');
e.setAttribute('id', 'loginbg');
window.nuLoginU = window.nuLoginU === undefined ? '' : window.nuLoginU;
window.nuLoginP = window.nuLoginP === undefined ? '' : window.nuLoginP;
$('body').html(H);
if (nuIsMobile()) {
$('body').css('width', 300).css('height', 300);
}
if (window.nuLoginU == '' && window.nuLoginP == '') {
$('#nuusername').nuSetFocus();
}
if (window.nuLoginU != '' && window.nuLoginP == '') {
$('#nuusername').val(window.nuLoginU);
$('#nupassword').nuSetFocus();
}
if (window.nuLoginU != '' && window.nuLoginP != '') {
$('#nuusername').val(window.nuLoginU);
$('#nupassword').val(window.nuLoginP);
nuLoginRequest();
}
if (sessionStorage.logout == 'true') {
nuMessage(['You have been logged out']);
}
sessionStorage.logout = '';
}
function nuSubmit(e) {
if (e.key == 'Enter') {
$('#submit').trigger("click");
}
}
function nuArrangingObjects(recordId) {
recordId = nuDefine(recordId, nuRecordId());
return recordId == '-2';
}
function nuCanArrangeObjects() {
const hasObjects = nuSERVERRESPONSE.objects && nuSERVERRESPONSE.objects.length > 0;
const isNotPortraitScreen = !window.nuPORTRAITSCREEN;
const isNotMobileView = !nuUseMobileView();
return nuGlobalAccess() && hasObjects && isNotPortraitScreen && isNotMobileView && !nuArrangingObjects();
}
function nuPopup(formId, recordId, filter) {
nuCursor('progress');
if (!nuGlobalAccess() && formId == 'nuobject') { return; }
if (nuArrangingObjects(recordId) && !nuCanArrangeObjects()) { return; }
window.nuOPENER.push(new nuOpener('F', formId, recordId, filter));
const openerId = window.nuOPENER[window.nuOPENER.length - 1].id;
if (parent.window == window) {
let dialogLeft = nuIsMobile() ? 0 : 50;
window.nuDialog.createDialog(dialogLeft + window.scrollX, 25 + window.scrollY, 50, 50, '');
} else {
window.nuDialog.createDialog(0, 30, 50, 50, '');
}
$('#nuDragDialog')
.css('visibility', 'hidden')
.append('')
.prepend('');
if (window.nuOnPopupOpenedGlobal) {
nuOnPopupOpenedGlobal(formId, recordId, filter);
}
}
function nuOptionsListAction(f, r, filter, e) {
const isCtrlOrCmdPressed = nuIsCtrlOrCmdPressed(e);
if (!isCtrlOrCmdPressed) {
nuPopup(f, r, filter);
} else {
nuForm(f, r, filter, '', '');
}
}
//-- object for dragging dialog --//
function nuCreateDialog(t) {
this.startX = 0;
this.startY = 0;
this.moveX = 0;
this.moveY = 0;
this.title = t;
this.pos = {};
this.move = function (event) {
this.moveX = event.clientX - this.startX;
this.moveY = event.clientY - this.startY;
this.startX = event.clientX;
this.startY = event.clientY;
if (event.buttons == 1) {
this.moveDialog(event);
}
const dir = event.target.parentElement.baseURI.includes('nureportdesigner') ? '' : 'core/';
$('#dialogClose').attr("src", dir + "graphics/close" + (event.target.id === 'dialogClose' ? "_red" : "") + ".png");
}
this.click = function (event) {
if (event.target.id == 'dialogClose') {
if ($('#nuWindow').contents().find('#nuSaveButton.nuSaveButtonEdited').length > 0) {
if (!confirm(nuTranslate('Leave this form without saving?'))) {
return false;
}
}
this.closeDialog();
}
}
this.closeDialog = function () {
nuMessageRemove(true);
$('#nuDragDialog').remove();
$('#nuModal').remove();
$('body').off('.popup');
nuSetFocus(window.nuLastFocus);
};
this.down = function (event) {
window.nuCurrentID = event.target.id;
if (event.target.id == 'dialogTitleWords') {
$('#nuDragDialog').append('');
}
}
this.moveDialog = function (event) {
if (window.nuCurrentID === 'nuModal') {
return;
}
const dialog = document.getElementById('nuDragDialog');
if (dialog === null) return;
let style = dialog.style;
let newLeft = parseInt(style.left, 10) + this.moveX;
let newTop = parseInt(style.top, 10) + this.moveY;
if (event.target.classList.length === 0 && event.target.id !== 'nuSelectBox') {
style.left = newLeft + 'px';
style.top = newTop + 'px';
}
}
this.createDialog = function (l, t, w, h, title) {
var callerName = this.createDialog.caller.name;
nuDialog.dialog = callerName;
var e = document.createElement('div');
var translation = nuTranslate(title);
e.setAttribute('id', 'nuDragDialog');
let scrollHeight = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
);
$('body').append('')
.append(e);
var subDir = callerName == 'nuPopup' || callerName == 'nuBuildLookup' ? 'core/' : '';
$('#nuDragDialog').addClass('nuDragDialog nuDragNoSelect')
.css({
'left': l,
'top': t,
'width': w,
'height': h,
'background-color': '#fff',
'z-index': 3000,
'position': 'absolute',
'visibility': 'hidden'
})
.html(' ' + translation + '

')
const $body = $('body');
if (!$body.attr('data-nu-popup-events')) {
$body.attr('data-nu-popup-events', '')
.on('mousemove.popup', function (event) { nuDialog.move(event); })
.on('click.popup', function (event) { nuDialog.click(event); })
.on('mousedown.popup', function (event) { nuDialog.down(event); })
.on('mouseup.popup', function (event) { window.nuCurrentID = ''; $('#nuPopupModal').remove(); })
.on('dblclick.popup', function (event) { nuResizeWindow(event); })
}
this.startX = l;
this.startY = t;
}
}
function nuReformat(element) {
const $element = $('#' + element.id);
const formatType = $element.attr('data-nu-format');
const currentValue = $element.val();
if (!formatType || !currentValue) {
return currentValue;
}
const reapplyFormat = function (value, format) {
let rawValue = nuFORM.removeFormatting(value, format, element.id);
return nuFORM.addFormatting(rawValue, format);
};
const formattedValue = reapplyFormat(currentValue, formatType);
if (formatType.startsWith('D') && currentValue !== formattedValue) {
$element.val('');
if (window.nuFormatValueClearedGlobal) {
nuFormatValueClearedGlobal($element, currentValue);
}
if (window.nuFormatValueCleared) {
nuFormatValueCleared($element, currentValue);
}
} else if (formatType.startsWith('N')) {
$element.val(formattedValue);
}
}
function nuOpenAce(lang, obj) {
const ts = Date.now();
const theme = nuUXOptions.nuAceTheme || 'dawn';
window.nuAce = [lang, obj, theme];
window.open(`core/nuace.php?${ts}`);
}
function nuBindCtrlEvents() {
const nuCtrlKeydownListener = function (e) {
const isCtrlOrCmdPressed = nuIsCtrlOrCmdPressed(e);
if (e.key === 'F3' || (isCtrlOrCmdPressed && e.key === 'f')) { // exclude Ctrl + f
window.nuNEW = 0;
} else {
if (e.key == 'Control') {
window.nuNEW = 1;
}
}
}
const nuHtml = document.getElementById('nuhtml');
nuAddEventListenerOnce(nuHtml, 'keydown', function (e) {
if (e.isComposing || e.keyCode === 229) {
return;
}
if ((e.key === 'PageDown' || e.key === 'PageUp') && nuFormType() == 'browse') {
const $nuRecord = $("#nuRECORD");
const scrollBy = e.key === 'PageDown' ? 400 : -400;
$nuRecord.scrollTop($nuRecord.scrollTop() + scrollBy);
}
if (e.key == 'Escape') {
if (nuIsVisible('nuMessageDiv')) {
nuMessageRemove(true);
} else if (nuIsVisible('nuOptionsListBox')) {
$('#nuOptionsListBox').remove();
} else if (parent.$('#nuModal').length === 1) {
let ae = document.activeElement;
$(ae).trigger("blur").nuSetFocus();
if (nuFormsUnsaved() == 0) {
nuClosePopup();
// nuDialog.closeDialog();
} else {
if (confirm(nuTranslate('Leave this form without saving?'))) {
nuClosePopup();
}
}
} else if (nuFormType() == 'browse') {
nuSearchAction("");
}
}
const isCtrlOrCmdPressed = nuIsCtrlOrCmdPressed(e);
if (isCtrlOrCmdPressed && e.shiftKey) {
if (typeof nuSERVERRESPONSE === 'undefined') {
return;
}
window.nuNEW = 0;
const globalAccess = nuGlobalAccess();
const formId = nuFormId();
const formType = nuFormType();
const isBrowseOrEdit = formType === 'browse' || formType === 'edit';
const isEditOnly = formType === 'edit';
const isBrowseOnly = formType === 'browse';
const isLaunch = nuCurrentProperties().form_type === 'launch';
// Define actions in a more structured way to avoid redundancy
const actions = {
// Common actions for both 'browse' and 'edit'
'r': { action: () => nuGetBreadcrumb(), condition: true },
// Actions specific to 'browse' form type
...(isBrowseOnly && {
'c': { action: () => nuGetSearchList(), condition: true },
's': { action: () => nuSearchAction(), condition: true },
'a': { action: () => nuAddAction(), condition: true },
'p': { action: () => nuPrintAction(), condition: globalAccess },
'arrowright': { action: () => $('#nuNext').trigger('click'), condition: true },
'arrowleft': { action: () => $('#nuLast').trigger('click'), condition: true },
'end': { action: () => $('#nuEnd i').trigger('click'), condition: true },
'home': { action: () => $('#nuFirst i').trigger('click'), condition: true }
}),
// Actions specific to 'edit' form type
...(isEditOnly && {
'a': { action: () => nuPopup(formId, "-2"), condition: nuCanArrangeObjects() },
'q': { action: () => nuPopup("nupassword", "", ""), condition: !globalAccess },
'h': { action: () => nuPopup('nuobject', '-1', ''), condition: globalAccess },
'g': { action: () => nuForm("nuobjectgrid", formId, "", "", 2), condition: globalAccess },
's': { action: () => { $(":focus").trigger("blur"); nuSaveAction(); }, condition: true },
'c': { action: () => { if (!isLaunch) { nuCloneAction() } }, condition: true },
'y': { action: () => { if (!isLaunch) { nuDeleteAction() } }, condition: true },
'arrowright': { action: () => nuSelectNextTab(1), condition: true },
'arrowleft': { action: () => nuSelectNextTab(-1), condition: true },
'?': { action: () => nuOpenFormHelp(), condition: true }
}),
// Actions available on 'browse' or 'edit' form types
...(isBrowseOrEdit && {
'f': { action: () => nuPopup("nuform", formId), condition: globalAccess },
'k': { action: () => nuPopup("nupromptgenerator", "-1", ''), condition: globalAccess },
'o': { action: () => nuPopup("nuobject", "", formId), condition: globalAccess },
'm': { action: () => nuShowFormInfo(), condition: globalAccess },
'v': { action: () => nuShowVersionInfo(), condition: globalAccess },
'e': { action: () => nuVendorLogin('PMA'), condition: globalAccess },
'j': { action: () => nuForm("nusession", "", "", "", 2), condition: globalAccess },
'q': { action: () => nuVendorLogin("TFM"), condition: globalAccess && isBrowseOrEdit },
'b': { action: () => nuRunBackup(), condition: globalAccess },
'u': { action: () => nuForm('nusetup', '1', '', '', 2), condition: globalAccess },
'd': { action: () => nuPopup("nudebug", ""), condition: globalAccess },
'z': { action: () => nuPopup("nucloner", "-1"), condition: globalAccess },
'x': { action: () => nuPrettyPrintMessage(e, nuCurrentProperties()), condition: globalAccess },
'l': { action: () => nuAskLogout(), condition: true }
}),
};
// Execute action based on key press if condition is met
const key = e.key.toLowerCase();
const action = actions[key];
if (action?.condition) {
e.preventDefault();
action.action();
}
let nosearch = window.nuFORM.getProperty('nosearch_columns');
let searchIndex = -1;
//Numbers
const numberCode = e.code.replace('Digit', '');
if (numberCode >= "1" && numberCode <= "9") {
searchIndex = Number(numberCode) - 1;
}
if (searchIndex != -1) {
if ($.inArray(searchIndex, nosearch) != '-1') {
nosearch.pop(searchIndex);
$('#nusort_' + searchIndex).removeClass('nuNoSearch');
} else {
nosearch.push(searchIndex);
$('#nusort_' + searchIndex).addClass('nuNoSearch');
}
}
window.nuFORM.setProperty('nosearch_columns', nosearch);
}
}, { passive: false }, 'nu-keydown-added');
const nuCtrlKeyupListener = function () {
window.nuNEW = 0;
}
$(document).on('keydown.nubindctrl', nuCtrlKeydownListener);
$(document).on('keyup.nubindctrl', nuCtrlKeyupListener);
}
function nuUnbindDragEvents() {
$(document).off('.nubindctrl');
}
function nuTranslate(obj) {
const isEnglish = nuUserLanguage() === '';
if (Array.isArray(obj)) {
if (isEnglish) {
return obj;
}
let arr = obj;
arr.forEach(function (item, index) {
const l = nuLANGUAGE.find(elem => elem.english === item);
arr[index] = !l ? item : l.translation;
})
return arr;
} else {
if (!obj) return '';
str = String(obj);
if (str.charAt(0) == '|') return str.substring(1);
if (isEnglish) {
return str;
}
const l = nuLANGUAGE.find(elem => elem.english === str);
return !l ? str : l.translation;
}
}
function nuTranslateToEnglish(str) {
if (!str) return '';
str = String(str);
if (str.charAt(0) === '|') return str.substring(1);
const l = nuLANGUAGE.find(({ translation }) => translation === str);
return l ? l.english : str;
}
function nuIsOpener() {
return window.opener !== null;
}
function nuPreview(a) {
const r = nuRecordId();
if (r === '-1') {
alert(nuTranslate('Form must be saved first..'));
return;
}
const arg = a === undefined ? '-3' : '';
nuPopup(r, arg);
}
function nuPopEvent(e, formId, nuEvent) {
const isCtrlOrCmdPressed = nuIsCtrlOrCmdPressed(e);
const recordId = nuRecordId();
const id = `${recordId}_${nuEvent}`;
let filter;
switch (formId) {
case 'nuphp':
filter = 'justphp';
break;
case 'nuselect':
filter = 'justsql';
break;
default:
console.warn(`nuPopEvent: unknown formId "${formId}"`);
return;
}
if (!isCtrlOrCmdPressed) {
nuPopup(formId, id, filter);
} else {
nuForm(formId, id, filter, '', '');
}
}
function nuIsCtrlOrCmdPressed(e) {
return e ? (nuIsMacintosh() ? e.metaKey : e.ctrlKey) : false;
}
function nuPopPHP(e, nuEvent) {
nuPopEvent(e, 'nuphp', nuEvent);
}
function nuPopSQL(e, nuEvent) {
nuPopEvent(e, 'nuselect', nuEvent);
}
function nuGetLookupFields(id) {
const prefix = id.slice(0, -4);
const $id = $('#' + id);
const lookupFields = [];
if ($id.length === 1) {
const type = $id.attr('data-nu-type');
if (type === 'subform') {
lookupFields.push(prefix, id, prefix + 'description');
} else {
lookupFields.push('nunosuchfield', id, 'nunosuchfield');
}
}
return lookupFields;
}
function nuObjectComponents(id) {
let componentIds = [id, `label_${id}`];
let type = '';
const element = $(`#${id}`);
if (element.attr('data-nu-type') === 'lookup') {
componentIds.push(`${id}code`, `${id}button`, `${id}description`);
type = 'lookup';
} else
if (element.hasClass('select2-hidden-accessible')) {
componentIds.push(`${id}_select2`);
type = 'select2';
}
return {
componentIds,
type
};
}
function nuEnable(i, enable) {
if (enable === false) {
nuDisable(i);
return;
}
const ids = Array.isArray(i) ? i : [i];
$.each(ids, function (index) {
const id = ids[index];
let { componentIds, type } = nuObjectComponents(id);
for (let c = 0; c < componentIds.length; c++) {
if (c === 1) {
continue;
} // skip label
let $current = $('#' + componentIds[c]);
$current
.removeClass('nuReadonly')
.prop('readonly', false)
.prop('disabled', false);
if (type === 'Lookup' && c === 2) { //-- button
$current.on("click", () => nuBuildLookup(componentIds[c], ""));
}
}
});
}
function nuDisable(id) {
const ids = Array.isArray(id) ? id : [id];
$.each(ids, function (index) {
const id = ids[index];
const { componentIds } = nuObjectComponents(id);
for (let c = 0; c < componentIds.length; c++) {
if (c === 1) {
continue;
} // skip label
let $component = $('#' + componentIds[c]);
$component.addClass('nuReadonly')
let result = true;
if (window.nuOnDisableGlobal) {
result = nuOnDisableGlobal(id, $component);
}
if (result !== false) {
$component
.prop('readonly', true)
.prop('disabled', true);
}
if (c === 2) { //-- button
$component.off();
}
}
});
}
function nuReadonly(id, readonly = true) {
let { componentIds } = nuObjectComponents(id);
componentIds.forEach((component, index) => {
// Skip label by index
if (index === 1) return;
$(`#${component}`)
.toggleClass('nuReadonly', readonly)
.prop('readonly', readonly);
});
}
function nuShow(ids, visible, openTab) {
const elementIds = Array.isArray(ids) ? ids : [ids];
let shownCounter = 0;
for (const elementId of elementIds) {
if (visible === false) {
nuHide(elementId);
} else {
const { componentIds } = nuObjectComponents(elementId);
for (const componentId of componentIds) {
const nuTab = String($('#' + componentId).attr('data-nu-tab'));
if (nuIsHidden(componentId)) {
if (nuTab[0] === 'x') {
$('#' + componentId)
.attr('data-nu-tab', nuTab.substring(1))
.show();
} else {
$('#' + componentId).show();
}
shownCounter++;
}
}
}
if (openTab !== false && shownCounter > 0 && $('.nuTabSelected').length > 0) {
nuOpenTab($('.nuTabSelected')[0].id.substr(5));
}
}
}
function nuHide(ids) {
let elementIds = [];
if (!Array.isArray(ids)) {
elementIds.push(ids);
} else {
elementIds = ids;
}
for (let i = 0; i < elementIds.length; i++) {
const { componentIds } = nuObjectComponents(elementIds[i]);
for (let j = 0; j < componentIds.length; j++) {
const elementId = componentIds[j];
const nuTab = String($('#' + elementId).attr('data-nu-tab'));
if (nuTab[0] === 'x') {
$('#' + elementId).hide();
} else {
$('#' + elementId)
.attr('data-nu-tab', 'x' + nuTab)
.hide();
}
}
}
}
function nuRemove(id) {
const elementIds = Array.isArray(id) ? id : [id];
for (const elementId of elementIds) {
const { componentIds } = nuObjectComponents(elementId);
for (const componentId of componentIds) {
$('#' + componentId).remove();
}
}
}
function nuIsVisible(id) {
if (!id) return;
const $id = typeof id === 'string' ? $('#' + id) : id;
if ($id.length === 0) return null;
const display = $id.css('display');
const visibility = $id.css('visibility');
const isHidden = $id.is(':hidden');
return display !== 'none' && visibility !== 'hidden' && !isHidden;
}
function nuIsHidden(id) {
return !nuIsVisible(id);
}
function nuIsEnabled(id) {
const $id = $('#' + id);
return !$id.is(':disabled') && !$id.hasClass('nuReadonly');
}
function nuIsDisabled(id) {
let $id = $('#' + id);
return $id.is(':disabled') || $id.hasClass('nuReadonly');
}
function nuAddThousandSpaces(numberString, delimiter) {
return numberString.replace(/\B(?=(\d{3})+(?!\d))/g, delimiter);
}
function nuResizeWindow(e) {
if (e.target.id !== 'dialogTitleWords') return;
const dialog = $('#nuDragDialog');
const dialogLeft = parseInt(dialog.css('left'), 10);
const win = $('#nuWindow');
const dragOptionsBox = $('.nuDragOptionsBox');
if (dialogLeft === 2) {
const contentWin = nuGetNuDragDialogIframes()[0].contentWindow;
dialog.css(contentWin.nuDialogSize);
win.css(contentWin.nuWindowSize);
} else {
dialog.css({
top: 0,
left: 2,
width: window.innerWidth - 30,
height: window.innerHeight
});
const dialogWidth = dragOptionsBox.length ? parseInt(dragOptionsBox.css('width'), 10) : 0;
win.css({
top: 30,
width: parseInt(dialog.css('width'), 10) - dialogWidth - 10,
height: parseInt(dialog.css('height'), 10) - 50
});
}
}
function nuGetFunctionList() {
var f = '';
for (var k in window) {
if (Object.prototype.hasOwnProperty.call(window, k)) {
if (String(k).startsWith('nu')) {
f += k + "\n";
}
}
}
return f;
}
function nuID() {
nuSetSuffix();
window.nuUniqueID = 'c' + String(Date.now());
return window.nuUniqueID + String(window.nuSuffix);
}
function nuSetSuffix(a) {
if (arguments.length == 1) {
window.nuSuffix = a;
}
if (window.nuSuffix == 9999) {
window.nuSuffix = 0
} else {
window.nuSuffix++;
}
}
function nuWhen(timestamp) {
if (!timestamp) return;
const secondsElapsed = Math.ceil((Date.now() / 1000) - timestamp);
const timeUnit = secondsElapsed === 1 ? 'second' : 'seconds';
return `${secondsElapsed} ${timeUnit} ago`;
}
function nuSpaces(s) {
return String(' ').repeat(s);
}
function nuAddEditFieldsToHash(w) {
const { fields, rows } = nuFORM.data()[0];
const rowData = rows[0];
fields.slice(2).forEach((field, index) => {
w[field] = rowData[index + 2];
});
return w;
}
function nuOnFocus(e) {
$('.nuTabSelected').attr('nu-data-active-element', document.activeElement.id);
}
function nuClick(e) {
const target = $(e.target);
const parentClasses = target.parents().map(function () {
return this.className;
}).get();
if (!parentClasses.includes('ctxmenu')) {
nuContextMenuClose();
}
if (!target.closest('.nuOptionsItem, .nuSearchCheckbox, .nuOptionsList').length) {
$('#nuSearchList').remove();
}
if (!target.is('.nuIcon, .nuOptionsList, .nuOptionsListTitle')) {
$('#nuOptionsListBox').remove();
}
if (target.attr('id') !== 'nuMessageDiv' && !parentClasses.includes('nuMessage') && target.attr('data-nu-option-title') !== 'Help') {
nuMessageRemove();
window.top.document.nuHideMessage = true;
}
}
function nuAddSlashes(s) {
return String(s).replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
}
function nuOpenTab(i) {
$('#nuTab' + i).trigger("click");
}
function nuSelectedTabNumber(parent = null) {
const nuForm = parent === null ? window.nuFORM : window.parent.nuFORM;
const tabStart = nuForm.getProperty('tab_start');
return tabStart.length > 0 ? tabStart[0].tabNumber : null;
}
function nuSelectedTabId(parent = null) {
const n = nuSelectedTabNumber(parent);
if (n === null) {
return null;
}
const selectorBase = parent === null ? $(`#nuTab${n}`) : parent.$(`#nuTab${n}`);
return selectorBase.attr('data-nu-tab-id');
}
function nuSelectedTab(parent = null) {
const n = nuSelectedTabNumber(parent);
if (n === null) return null;
return parent === null ? $('#nuTab' + n) : parent.$('#nuTab' + n);
}
function nuSelectedTabTitle(parent = null) {
const n = nuSelectedTabNumber(parent)
if (n === null) return null;
return parent === null ? $('#nuTab' + n).html() : parent.$('#nuTab' + n).html();
}
function nuSelectNextTab(i, includeInvisible = false, byUser = true) {
const selectedTab = $('.nuTabSelected')[0];
const selectedTabId = selectedTab.id.substring(5);
let nextTabId = parseInt(selectedTabId, 10) + i;
let element;
while (!includeInvisible && (element = document.getElementById('nuTab' + nextTabId)) && !nuIsVisible(element.id)) {
nextTabId += i;
}
if (element) {
nuSelectTab(element, byUser);
}
}
function nuSelectToArray(id, type = 'value', selectedOnly = true) {
let result = [];
// Choose whether to loop only selected options or all options
const selector = selectedOnly
? '#' + id + ' option:selected'
: '#' + id + ' option';
$(selector).each(function () {
var txt = $(this).text();
// Skip blank-text options in all cases
if (txt.trim() === '') return;
switch (type) {
case 'text':
result.push(txt);
break;
case 'value':
result.push($(this).val());
break;
case 'index':
// +1 if you want 1-based indexing
result.push($(this).index() + 1);
break;
default:
throw new Error('nuSelectToArray: unknown type "' + type + '"');
}
});
return result;
}
function nuModifyHolders(action, ...args) {
const actions = {
0: '#nuActionHolder',
1: '#nuBreadcrumbHolder',
2: '#nuTabHolder',
};
args.forEach(arg => {
if (actions[arg]) $(actions[arg])[action]();
});
}
function nuHideHolders(...args) {
nuModifyHolders('hide', ...args);
}
function nuRemoveHolders(...args) {
nuModifyHolders('remove', ...args);
}
function nuAttachFontAwesome(id, iconClass, size = 'medium', appendToEnd = false) {
const $target = $(typeof id === 'string' ? `#${id}` : id);
if (!$target.length) return;
const text = $target.text().trim();
if (!text) {
$target.css('padding', '0 9px');
}
const fontSizeStyle =
size === 'small' ? 'font-size: small;'
: size === 'large' ? 'font-size: x-large;'
: size === 'medium' ? ''
: `font-size: ${size};`;
const marginStyle = text
? (appendToEnd ? 'margin-left: 3px;' : 'margin-right: 3px;')
: '';
const combinedStyle = `${fontSizeStyle}${marginStyle}`;
const styleAttr = combinedStyle ? ` style="${combinedStyle}"` : '';
const iconHtml = ``;
const sep = text ? ' ' : '';
const content = appendToEnd
? sep + iconHtml
: iconHtml + sep;
if (appendToEnd) {
$target.append(content);
} else {
$target.prepend(content);
}
}
function nuAttachHTML(id, html, appendToEnd = false) {
const target = id instanceof jQuery ? id : $(`#${id}`);
if (target.length === 0) {
console.warn('Target element not found.');
return;
}
const content = appendToEnd ? ` ${html}` : `${html} `;
appendToEnd ? target.append(content) : target.prepend(content);
}
function nuCreateAppendHTML(htmlStr) {
var df = document.createDocumentFragment()
, temp = document.createElement('div');
temp.innerHTML = htmlStr;
while (temp.firstChild) {
df.appendChild(temp.firstChild);
}
return df;
}
function nuAttachFile(id, name) {
let cssProperties = {
'background-repeat': 'no-repeat',
'padding': '0px',
'text-align': 'left'
};
if (window.nuGraphics.indexOf(name + '.png') !== -1) {
$('#' + id).css({
...cssProperties,
'background-image': `url("graphics/${name}.png")`
});
} else if (nuImages[name] !== undefined) {
let p = JSON.parse(g);
let b = atob(p.file);
$('#' + id).css({
...cssProperties,
'background-image': `url("${b}")`
});
}
}
function nuButtonIcon(id) {
$(id).css({
'text-align': 'left',
'padding': '0px 0px 0px 35px',
'background-size': '30px',
'background-repeat': 'no-repeat'
});
}
function nuButtonLoading(buttonId, spinning = true, autoEnableAfterSeconds = 0) {
const button = document.getElementById(buttonId);
if (spinning) {
if (!button || nuIsDisabled(button.id)) return;
} else {
if (!button) return;
}
// clear any old timers/monitors
if (button._spinnerTimer) {
clearTimeout(button._spinnerTimer);
delete button._spinnerTimer;
}
if (button._spinnerMonitor) {
clearInterval(button._spinnerMonitor);
delete button._spinnerMonitor;
}
// find the “real” icon (if any) so we can hide it
const originalIcon = button.querySelector('i:not([nu-data-spinner])');
if (spinning) {
button.dataset.spinnerStart = Date.now();
button.disabled = true;
button.classList.add('disabled');
if (originalIcon) originalIcon.style.display = 'none';
// only add one spinner
if (!button.querySelector('[nu-data-spinner]')) {
// create the spinner
const spinner = document.createElement('i');
spinner.className = 'fa-width-auto fa fa-spinner fa-spin';
spinner.setAttribute('nu-data-spinner', 'true');
// decide where to put it:
const label = button.querySelector('.nuButtonLabel');
if (label) {
// insert right before the text label
label.parentNode.insertBefore(spinner, label);
// preserve a bit of spacing
label.parentNode.insertBefore(document.createTextNode(' '), label);
} else {
// no label ⇒ icon-only button
button.appendChild(spinner);
}
}
// if we should auto-re-enable later...
if (autoEnableAfterSeconds > 0) {
// watch for the button being removed from the DOM
button._spinnerMonitor = setInterval(() => {
if (!document.getElementById(buttonId)) {
clearInterval(button._spinnerMonitor);
clearTimeout(button._spinnerTimer);
delete button._spinnerMonitor;
delete button._spinnerTimer;
}
}, 300);
button._spinnerTimer = setTimeout(() => {
clearInterval(button._spinnerMonitor);
delete button._spinnerMonitor;
const stillThere = document.getElementById(buttonId);
const started = Number(button.dataset.spinnerStart || 0);
if (stillThere && (Date.now() - started >= autoEnableAfterSeconds * 1000)) {
nuButtonLoading(buttonId, false);
}
}, autoEnableAfterSeconds * 1000);
}
} else {
// turn it off
button.disabled = false;
button.classList.remove('disabled');
// remove the spinner
const oldSpinner = button.querySelector('[nu-data-spinner]');
if (oldSpinner) oldSpinner.remove();
// bring back the original icon
if (originalIcon) originalIcon.style.display = '';
delete button.dataset.spinnerStart;
}
}
function nuChart(chartId, chartType, dataArray, chartTitle, xAxisTitle, yAxisTitle, seriesType, isStacked) {
const chartElement = document.getElementById(chartId);
if (!chartElement) return;
const data = eval(dataArray);
if (!data || data.length === 0) return;
try {
google.charts.load('current', {
packages: ['corechart']
});
} catch (error) {
return;
}
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
const dataTable = google.visualization.arrayToDataTable(data);
const chartWrapper = new google.visualization.ChartWrapper({
chartType,
dataTable,
containerId: chartId,
options: {
title: chartTitle,
vAxis: {
title: yAxisTitle
},
hAxis: {
title: xAxisTitle
},
seriesType,
isStacked,
},
});
const readyListener = google.visualization.events.addListener(chartWrapper, 'ready', () => {
if (window.nuChartOnReady) {
google.visualization.events.removeListener(readyListener);
window.nuChartOnReady(chartId, chartWrapper);
}
});
chartWrapper.draw();
window[`${chartId}_wrapper`] = chartWrapper;
}
}
function nuEncode(s) {
return window.btoa(unescape(encodeURIComponent(s)))
}
function nuDecode(s) {
return decodeURIComponent(escape(window.atob(s)))
}
function nuAddRow(id, setFocus = true) {
const o = nuSubformObject(id);
const index = nuPad3(o.rows.length - 1) + o.fields[1];
$(`#${id}${index}`).trigger("change");
if (setFocus) {
const newIndex = nuPad3(o.rows.length) + o.fields[1];
const $newInput = $(`#${id}${newIndex}`);
$newInput.nuSetFocus();
}
}
function nuAccessLevelGroup() {
return nuSERVERRESPONSE.access_level_group;
}
function nuAccessLevelCode() {
return nuSERVERRESPONSE.access_level_code;
}
function nuAccessLevelId() {
return nuSERVERRESPONSE.access_level_id;
}
function nuUserName() {
return nuSERVERRESPONSE.user_name;
}
function nuUserFirstName() {
return nuSERVERRESPONSE.user_first_name;
}
function nuUserLastName() {
return nuSERVERRESPONSE.user_last_name;
}
function nuUserPosition() {
return nuSERVERRESPONSE.user_position;
}
function nuUserDepartment() {
return nuSERVERRESPONSE.user_department;
}
function nuUserA11Y() {
return nuSERVERRESPONSE.user_a11y;
}
function nuUserTeam() {
return nuSERVERRESPONSE.user_team;
}
function nuUserCode() {
return nuSERVERRESPONSE.user_code;
}
function nuUserAdditional1() {
return nuSERVERRESPONSE.user_additional1;
}
function nuUserAdditional2() {
return nuSERVERRESPONSE.user_additional2;
}
function nuUserPermissions() {
return nuSERVERRESPONSE.user_permissions.nuStringToArray();
}
function nuUserHasPermission(item, userOnly = false) {
const hasPermission = nuUserPermissions().indexOf(item) !== -1;
if (userOnly === false && nuGlobalAccess()) {
return true;
}
return hasPermission;
}
function nuUserId() {
return nuSERVERRESPONSE.user_id;
}
function nuUserLogin() {
return nuSERVERRESPONSE.login_name;
}
function nuUserLanguage() {
if (typeof nuSERVERRESPONSE !== 'undefined') {
const l = nuSERVERRESPONSE.language;
return l === null ? '' : l;
} else {
return '';
}
}
function nuDatabaseName() {
return nuSERVERRESPONSE.db_name;
}
function nuDatabaseType() {
return nuSERVERRESPONSE.db_type;
}
function nuMSSQL() {
return nuSERVERRESPONSE.db_type == 'sqlsrv';
}
function nuClosePopup() {
parent.$('#nuModal').remove();
parent.$('#nuDragDialog').remove();
}
function nuStopClick(e) {
const isCtrlOrCmdPressed = nuIsCtrlOrCmdPressed(e);
if (window.nuCLICKER != '' && !isCtrlOrCmdPressed) {
$(e.target).prop('onclick', null).off('click');
}
}
function nuIsSaved() {
return window.nuSAVED;
}
function nuAscendingSortColumn(a, b) {
if (a.value < b.value) { return -1; }
if (a.value > b.value) { return 1; }
return 0;
}
function nuDecendingSortColumn(b, a) {
if (a.value < b.value) { return -1; }
if (a.value > b.value) { return 1; }
return 0;
}
function nuAscendingSortNumberColumn(a, b) {
if (Number(a.value) < Number(b.value)) { return -1; }
if (Number(a.value) > Number(b.value)) { return 1; }
return 0;
}
function nuDecendingSortNumberColumn(b, a) {
if (Number(a.value) < Number(b.value)) { return -1; }
if (Number(a.value) > Number(b.value)) { return 1; }
return 0;
}
function nuEmbedObject(json, containerId, width, height) {
if (json === '') { return; }
width = nuDefine(width, 300);
height = nuDefine(height, 300);
const fileData = JSON.parse(json);
const fileType = fileData.type;
let dataUrl = atob(fileData.file);
if (!dataUrl.startsWith('data:')) {
dataUrl = `data:${fileType};base64,${fileData.file}`;
}
const embedElement = document.createElement("EMBED");
embedElement.setAttribute("type", fileType);
embedElement.setAttribute("src", dataUrl);
if (width !== -1) embedElement.setAttribute("width", width + "px");
if (height !== -1) embedElement.setAttribute("height", height + "px");
$('#' + containerId).html('');
document.getElementById(containerId).appendChild(embedElement);
}
function nuVendorLogin(appId, table) {
if (nuMSSQL() && appId === 'PMA') {
nuMessage(nuTranslate('Information'), nuTranslate('Not supported'));
return;
}
const tableName = table || nuSERVERRESPONSE.table;
const params = new URLSearchParams({
sessid: window.nuSESSION,
appId: appId,
table: tableName,
timezone: nuSERVERRESPONSE.timezone
});
const url = `core/nuvendorlogin.php?${params.toString()}`;
window.open(url);
}
function nuIsMobile() {
return navigator.userAgent.toLowerCase().split('mobile').length > 1;
}
function nuIsMacintosh() {
if (navigator.userAgentData?.platform) {
return /mac/i.test(navigator.userAgentData.platform);
}
return /macintosh|mac os x/i.test(navigator.userAgent);
}
function nuTransformScale() {
if ($('body').css('transform') == 'none') {
return 1;
}
return Number($('body').css('transform').split('(')[1].split(',')[0]);
}
function nuStopBrowserResize() {
if (nuFormType() == 'browse') {
nuFORM.breadcrumbs[nuFORM.breadcrumbs.length - 1].refreshed = 1;
}
}
function nuDisableBrowseResize() {
if (nuFormType() == 'browse') {
$("div[id^='nuBrowseTitle']")
.off('mousedown.nuresizecolumn')
.off('touchstart.nuresizecolumn')
.off('touchmove.nuresizecolumn')
.off('touchstart.nuresizecolumn');
}
}
function nuAddEventListenerOnce(target, eventType, eventFunction, options, eventClass) {
if (!target.classList.contains(eventClass)) {
target.addEventListener(eventType, eventFunction, options);
target.classList.add(eventClass);
}
}
function nuDragTitleEvents() {
if (nuFormType() != 'browse') {
return;
}
let colWidths = nuFORM.getCurrent().column_widths || nuGetColumWidths();
nuSetBrowseColumns(colWidths);
const body = document.getElementById('nubody');
const browseTitle = document.querySelectorAll('.nuBrowseTitle');
nuAddEventListenerOnce(body, 'mousemove', function (event) {
nuDragBrowseColumn(event, 'pointer');
}, { passive: true }, 'nu-mousemove-added');
nuAddEventListenerOnce(body, 'mouseup', function (event) {
nuEndBrowseResize();
}, { passive: true }, 'nu-mouseup-added');
browseTitle.forEach(elem => {
nuAddEventListenerOnce(elem, 'mousedown', function (event) {
nuDownBrowseResize(event, 'pointer');
}, { passive: true }, 'nu-mousedown-added');
nuAddEventListenerOnce(elem, 'touchstart', function (event) {
nuDownBrowseResize(event, 'finger_touch');
}, { passive: true }, 'nu-touchstart-added');
nuAddEventListenerOnce(elem, 'touchmove', function (event) {
nuDragBrowseColumn(event, 'finger_touch');
}, { passive: true }, 'nu-touchmove-added');
nuAddEventListenerOnce(elem, 'touchend', function (event) {
nuEndBrowseResize(event);
}, { passive: true }, 'nu-touchend-added');
nuAddEventListenerOnce(elem, 'touchcancel', function (event) {
nuEndBrowseResize(event);
}, { passive: true }, 'nu-touchcancel-added');
});
}
function nuRemovePX(s) {
return Number(String(s).split('px')[0]);
}
function nuImportUsersFromCSV(file, delimiter) {
file = nuDefine(file, 'user_import.csv');
nuSetProperty('nu_import_users_file', file);
nuSetProperty('nu_import_users_delimiter', delimiter);
nuRunPHP('nu_import_users', '', 0);
}
function nuIsIframe() {
return parent.window.nuDocumentID != window.nuDocumentID && parent.window.nuDocumentID !== undefined;
}
function nuIsPopup() {
return !!(window.frameElement && $(window.frameElement).closest('.nuDragDialog').length > 0);
}
function nuPreventButtonDblClick() {
$('.nuActionButton, .nuButton, #nuLogout').not(".nuAllowDblClick").on("click", function () {
const button = $(this);
if (button.hasClass('nuReadonly') || button.hasClass('nuAllowDblClick')) {
return;
}
const id = button.attr("id");
button.addClass('nuPreventDblClick');
nuDisable(id);
setTimeout(function () {
nuEnable(id);
button.removeClass('nuPreventDblClick');
}, 1300);
});
}
function nuAddBackButton() {
if ($('.nuBreadcrumb').length > 0) {
nuAddActionButton('Back');
}
}
function nuEnableBrowserBackButton() {
if (window.history.length > 1) {
window.history.pushState({ page: 1 }, "", "");
} else {
window.history.replaceState({ page: 1 }, "", "");
}
window.onpopstate = function (event) {
if (event) {
nuOpenPreviousBreadcrumb();
}
};
}
function nuSetBrowserTabTitle(prefix) {
var t = window.nuFORM.getProperty('title');
if (t === '') {
t = "Properties";
}
prefix = prefix === '' ? '' : prefix + ' - ';
document.title = prefix + t;
}
function nuSetPlaceholder(i, placeholder = null, translate = true) {
const $i = $('#' + i);
if (!placeholder) {
placeholder = $i.attr('data-nu-format').substring(2);
}
if (translate) {
placeholder = nuTranslate(placeholder);
}
$i.attr('placeholder', placeholder);
}
function nuSetToolTip(id, options, labelHover) {
if (options && typeof options === "object") {
nuSetAdvancedToolTip(id, options);
return;
}
const setToolTip = selector => {
$(selector)
.on("mouseenter", function () {
$(this).attr("title", nuTranslate(options));
})
.on("mouseleave", function () {
$(this).removeAttr("title");
});
};
setToolTip("#" + id);
if (labelHover) setToolTip("#label_" + id);
}
function nuSetAdvancedToolTip(selector, arg2 = {}, arg3 = {}) {
// Allow (selector, options) OR (selector, text, options)
let options;
if (typeof arg2 === 'string') {
options = { ...arg3, content: arg2 };
} else {
options = arg2 || {};
}
const defaults = { createIcon: false };
let elements = nuElement(selector);
if (elements.length === 0 && typeof selector === 'string') {
elements = Array.from(document.querySelectorAll(`#${selector}`));
}
let cssSelector = selector;
if (typeof selector === 'string' && !/^[#.\[]/.test(selector)) {
cssSelector = `#${selector}`;
}
const merged = Object.fromEntries(
Object.entries({ ...defaults, ...options, selector: cssSelector }).filter(([, v]) => v != null)
);
if (merged.content != null && merged.content !== '') {
elements.forEach(el => el.setAttribute('nu-tooltip-icon', merged.content));
}
nuAttachToolTip(merged);
}
function nuAddDatalist(i, arr, showAllOnArrowClick = true) {
if (!Array.isArray(arr)) {
console.error(`Argument #2 is not an array in nuAddDatalist() for object ${i}`);
return;
}
let datalist = document.getElementById(`${i}_datalist`);
if (!datalist) {
datalist = document.createElement('datalist');
datalist.id = `${i}_datalist`;
document.body.appendChild(datalist);
if (showAllOnArrowClick) nuDatalistShowAllOnArrowClick(i);
} else {
datalist.innerHTML = '';
}
arr.forEach(item => {
let option = document.createElement('option');
if (Array.isArray(item)) {
// Use the first element as the option value.
option.value = item[0];
// If more than one element exists, join the rest as the option text.
if (item.length > 1) {
option.text = item.slice(1).join(' ');
}
} else {
// If the item is not an array, use it directly.
option.value = item;
}
datalist.appendChild(option);
});
// Update attributes of the input element.
const inputElement = document.getElementById(i);
inputElement.setAttribute('list', datalist.id);
inputElement.setAttribute('autocomplete', 'off');
}
function nuLabelOnTop(include, exclude, offsetTop = -18, offsetLeft = 0) {
include = include || nuSERVERRESPONSE.objects.map(obj => obj.id);
exclude = exclude || [];
for (let i = 0; i < include.length; i++) {
if (jQuery.inArray(include[i], exclude) == -1) {
$element = $('#' + include[i]);
$('#' + 'label_' + include[i]).css({
'top': $element.nuCSSNumber('top') + offsetTop
, 'left': $element.nuCSSNumber('left') + offsetLeft
, 'text-align': 'left'
});
$element.attr('data-nu-label-position', 'top');
}
}
}
jQuery.fn.nuLabelOnTop = function (offsetTop = -18, offsetLeft = 0) {
return this.each(function () {
$element = $(this);
$('#' + 'label_' + this.id).css({
'top': $element.nuCSSNumber("top") + offsetTop
, 'left': $element.nuCSSNumber("left") + offsetLeft
, 'text-align': 'left'
});
$element.attr('data-nu-label-position', 'top');
});
};
jQuery.fn.nuCSSNumber = function (prop) {
var v = parseInt(this.css(prop), 10);
return isNaN(v) ? 0 : v;
};
function nuEnableDisableAllObjects(enable, excludeTypes = [], excludeIds = []) {
const responseObjects = {
objects: [...nuSERVERRESPONSE.objects]
};
for (const obj of responseObjects.objects) {
if (!excludeTypes.includes(obj.type) && !excludeIds.includes(obj.id) && obj.type !== 'contentbox' && obj.type !== 'html') {
nuEnable(obj.id, enable);
}
}
}
function nuEnableAllObjects(excludeTypes, excludeIds) {
nuEnableDisableAllObjects(true, excludeTypes, excludeIds);
}
function nuDisableAllObjects(excludeTypes, excludeIds) {
nuEnableDisableAllObjects(false, excludeTypes, excludeIds);
}
function nuInsertTextAtCaret(id, textToInsert) {
const $textarea = $('#' + id);
const element = $textarea[0];
element.focus();
if (document.queryCommandSupported('insertText')) {
const selectionStart = element.selectionStart;
const selectionEnd = element.selectionEnd;
element.setSelectionRange(selectionStart, selectionEnd);
document.execCommand('insertText', false, textToInsert);
} else {
element.setRangeText(
textToInsert,
element.selectionStart,
element.selectionEnd,
'end'
);
}
$textarea.trigger("change");
}
function nuGetObjectId(id) {
const objects = window.nuSERVERRESPONSE?.objects;
if (!Array.isArray(objects)) {
return null;
}
const matchByObjectId = objects.find(item => item.object_id === id);
if (matchByObjectId) {
return matchByObjectId.id;
}
const matchById = objects.find(item => item.id === id);
if (matchById) {
return matchById.object_id;
}
return null;
}
function nuSetBrowseColumnSize(column, size) {
let contextWindow = nuIsIframe() ? parent.document.getElementById(window.frameElement.id).contentWindow : this;
const currentBreadcrumb = contextWindow.nuFORM.breadcrumbs[contextWindow.nuFORM.breadcrumbs.length - 1];
if (size === undefined) {
return currentBreadcrumb.column_widths[column];
}
currentBreadcrumb.column_widths[column] = size;
contextWindow.nuSetBrowseColumns(currentBreadcrumb.column_widths);
}
function nuSelectMultiWithoutCtrl(i, active) {
var id = i === undefined || i === null ? 'select' : '#' + i;
if (active == false) {
$(id + "[multiple] option").off('mousedown.selectmultinoctrl');
return;
}
$(id + "[multiple] option").on('mousedown.selectmultinoctrl', function (event) {
if (event.shiftKey) return;
event.preventDefault();
this.focus();
var scroll = this.scrollTop;
event.target.selected = !event.target.selected;
this.scrollTop = scroll;
$(this).parent().trigger("change");
});
}
function nuSelectRemoveEmpty(elementId, setIndex) {
const selector = elementId === undefined ? 'select' : `#${elementId}`;
$(`${selector} option`).each(function () {
const option = $(this);
if (option.val().trim() === "" && option.text().trim() === "") {
option.remove();
}
});
if (setIndex !== undefined) {
$(`${selector}`).each(function () {
$(this).prop('selectedIndex', setIndex);
});
}
}
function nuSelectRemoveOption(id, searchValue, findByText = false) {
const $select = typeof id === 'object' ? id : $('#' + id);
const selector = findByText ? `option:contains("${searchValue}")` : `[value="${searchValue}"]`;
const $option = $select.find(selector);
$option.remove();
return $select;
}
function nuSelectRemoveMultiple(i) {
var id = i ? '#' + i : 'select';
$(id + "[multiple]").prop('multiple', false).attr('size', '5');
}
function nuSelectSelectAll(id, value = true) {
const $id = $("#" + id);
$id.find('option:not(:empty)').prop('selected', value);
$id.trigger("change");
}
function nuSelectSelectedInfo(id) {
let option = {
values: [],
texts: []
};
$('#' + id + ' option:selected').each(function () {
let $this = $(this);
if ($this.val() !== '') {
option.values.push($this.val());
option.texts.push($this.text());
}
});
return option;
}
function nuSelectSelectedValueArray(id) {
return nuSelectSelectedInfo(id).values;
}
function nuSelectSelectedTextArray(id) {
return nuSelectSelectedInfo(id).texts;
}
function nuSelectSetIndex(id, index) {
$("#" + id).prop("selectedIndex", index).trigger('change');
}
function nuPasteText(id, callback) {
navigator.clipboard.readText()
.then(text => {
nuSetValue(id, text);
nuCallWindowFunction(callback, id, text);
});
}
function nuCopyToClipboard(obj) {
if (typeof obj !== 'string') {
obj = nujQueryObj(obj).val();
}
navigator.clipboard.writeText(obj).then(function () {
return true;
}, function () {
return false;
});
}
function nuCursor(c) {
document.documentElement.style.cursor = c;
parent.document.documentElement.style.cursor = c;
}
jQuery.fn.nuHighlight = function (pattern, accentInsensitive = true) {
if (!pattern || !pattern.length) return this;
// Flags + precomputed patterns
const useFold = accentInsensitive === true;
const upPat = pattern.toUpperCase();
const foldPat = useFold
? pattern
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toUpperCase()
: null;
function applyHighlight(node) {
let skip = 0;
// --- TEXT NODE: find a match ---
if (node.nodeType === 3) {
const text = node.data;
if (useFold) {
// Build folded string + index map
let folded = '', map = [];
for (let i = 0; i < text.length; i++) {
const decomp = text[i].normalize('NFD');
folded += decomp[0];
map.push(i);
}
folded = folded.toUpperCase();
const idx = folded.indexOf(foldPat);
if (idx >= 0) {
const startOrig = map[idx];
const endMap = idx + foldPat.length;
const endOrig = endMap < map.length ? map[endMap] : text.length;
// Split into [before][match][after]
const afterMatch = node.splitText(startOrig);
// const rest = afterMatch.splitText(endOrig - startOrig);
// Wrap only the matched text
const span = document.createElement('span');
span.className = 'nuBrowseSearch';
span.appendChild(afterMatch.cloneNode(true));
afterMatch.parentNode.replaceChild(span, afterMatch);
skip = 1;
}
} else {
// Plain case-insensitive
const upText = text.toUpperCase();
const idx = upText.indexOf(upPat);
if (idx >= 0) {
const afterMatch = node.splitText(idx);
const rest = afterMatch.splitText(pattern.length);
const span = document.createElement('span');
span.className = 'nuBrowseSearch';
span.appendChild(afterMatch.cloneNode(true));
afterMatch.parentNode.replaceChild(span, afterMatch);
skip = 1;
}
}
// --- ELEMENT NODE: recurse, skipping script/style ---
} else if (
node.nodeType === 1 &&
node.childNodes &&
!/(script|style)/i.test(node.tagName)
) {
for (let i = 0; i < node.childNodes.length; i++) {
i += applyHighlight(node.childNodes[i]) || 0;
}
}
return skip;
}
// Apply to each element in the jQuery collection
return this.each(function () {
applyHighlight(this);
});
};
function nuInputMaxLength(id, maxLength, labelId) {
const $input = $('#' + id);
// If maxLength is not provided, return the current maxlength of the input
if (maxLength === undefined) {
return parseInt($input.attr('maxlength'), 10) || null; // Return null if maxlength is not set
}
$input.attr('maxlength', maxLength);
if (labelId) {
const $label = $('#' + labelId);
$label.html(`${maxLength}/${maxLength}`);
$input.on('input', function () {
const textLen = maxLength - this.value.length;
$label.html(`${textLen}/${maxLength}`);
});
}
}
function nuDebugMode() {
return nuUXOptions.nuDebugMode;
}
function nuDebugOut(obj, i) {
if (nuDebugMode() && obj.length == 0) {
console.warn(nuTranslate('Object does not exist:'), i);
return true;
}
return false;
}
function nuGetValue(id, method) {
if (!id) return null;
const obj = $('#' + id);
if (nuDebugOut(obj, id)) return null;
if (obj.hasClass('nuHiddenLookup')) {
if (method === 'code') {
const codeId = id + 'code';
const codeObj = $('#' + codeId);
return codeObj.length ? codeObj.val() : null;
}
if (method === 'description') {
const descId = id + 'description';
const descObj = $('#' + descId);
return descObj.length ? descObj.val() : null;
}
}
if (obj.is(':checkbox') || obj.is(':radio')) {
return obj.is(":checked");
}
if (obj.hasClass('nuEditor')) {
return nuTinyMCEGetContent(id);
}
if (obj.is('select')) {
if (method === 'val' || method === undefined) {
return obj.val() === null ? '' : obj.val();
} else if (method === 'text') {
return obj.find("option:selected").text().nuReplaceNonBreakingSpaces();
}
}
if (!method && obj.is(':button')) {
return obj.text();
}
if (obj.is('label')) {
switch (method) {
case 'for':
return obj.attr('for') || null;
case 'html':
return obj.html();
default:
return obj.text();
}
}
switch (method) {
case 'html':
return obj.html();
case 'val':
return obj.val();
case 'text':
return obj.text();
default:
return obj.val();
}
}
function nuGetText(id) {
return nuGetValue(id, 'text');
}
function nuGetHTML(id) {
return nuGetValue(id, 'html');
}
function nuSetValue(id, value, method, change) {
var obj = $('#' + id);
if (id === undefined || nuDebugOut(obj, id)) return false;
change = (change || change === undefined);
if (obj.hasClass('nuHiddenLookup')) {
nuGetLookupId(value, id, method, change);
return true;
}
if (method === undefined && (obj.is('button') || (obj.is('input') && obj.attr('type') === 'button'))) {
if (obj.is('button')) {
const label = obj.find('.nuButtonLabel');
if (label.length) {
label.text(value);
} else {
obj.text(value);
}
} else {
// It's an
obj.val(value);
}
} else if (obj.is(':checkbox') || obj.is(':radio')) {
obj.prop('checked', value);
if (change) obj.trigger("change");
} else if (obj.is('select')) {
const hasEmptyOption = obj.find('option[value=""]').length > 0;
if (value == null || (value === '' && !hasEmptyOption)) {
obj.prop("selectedIndex", -1);
if (change) obj.trigger("change");
} else if (method === 'text') {
$('#' + id + ' option').each(function () {
if ($(this).text().nuReplaceNonBreakingSpaces() === value) {
$(this).prop("selected", "selected");
if (change) obj.trigger("change");
return false; // break loop
}
});
} else {
obj.val(value);
if (change) obj.trigger("change");
}
} else if (obj.hasClass('nuEditor')) {
nuTinyMCESetContent(id, value)
} else if (obj.is('label')) {
switch (method) {
case 'for':
obj.attr('for', value);
break;
case 'text':
obj.text(value);
break;
default:
nuSetLabelText(id, value, change);
}
} else {
switch (method) {
case 'html':
obj.html(value);
break;
case 'text':
obj.text(value);
break;
default:
obj.val(value);
if (change) obj.trigger("change");
}
}
return true;
}
function nuSetText(i, v) {
return nuSetValue(i, v, 'text');
}
function nuSetFocus(id) {
const $el = nujQueryObj(id);
/*
if (!$el || $el.length === 0) {
console.warn("Element not found.", id);
return false;
}
*/
$($el).trigger("focus");
return new Promise((resolve) => {
setTimeout(() => {
const active = document.activeElement;
if (!active || typeof active === "undefined") {
resolve(false);
} else {
resolve(active === $el[0]);
}
}, 0);
});
}
function nuCurrentDate(format) {
const d = new Date();
const
yyyy = d.getFullYear(),
mm = nuPad2(d.getMonth() + 1),
dd = nuPad2(d.getDate());
let dateFormat = `${yyyy}-${mm}-${dd}`;
if (format !== undefined) {
dateFormat = nuFORM.addFormatting(dateFormat, 'D|' + format);
}
return dateFormat;
}
function nuCurrentDateTime(format) {
const d = new Date();
const
yyyy = d.getFullYear(),
mm = nuPad2(d.getMonth() + 1),
dd = nuPad2(d.getDate()),
hh = nuPad2(d.getHours()),
nn = nuPad2(d.getMinutes()),
ss = nuPad2(d.getSeconds());
let dateTimeFormat = `${yyyy}-${mm}-${dd} ${hh}:${nn}:${ss}`;
if (format !== undefined) {
dateTimeFormat = nuFORM.addFormatting(dateTimeFormat, 'D|' + format);
}
return dateTimeFormat;
}
function nuSetDateValue(id, date) {
const obj = $('#' + id);
if (!id || nuDebugOut(obj, id)) return false;
date = date instanceof Date && !isNaN(date) ? date : new Date(date);
if (!(date instanceof Date) || isNaN(date)) {
date = new Date();
}
const df = date.getFullYear() + '-' + nuPad2(date.getMonth() + 1) + '-' + nuPad2(date.getDate());
const format = obj.attr('data-nu-format');
obj.val(nuFORM.addFormatting(df, format)).trigger("change");
return true;
}
function nuArrayIsUnique(arr) {
return arr.length === new Set(arr).size;
}
function nuArrayColumn(arr, n) {
return arr.map(x => x[n]);
}
function nuOpenWiki(page) {
window.open('https://wiki.nubuilder.cloud/index.php' + page);
}
function nuOpenFormHelp(page) {
const help = nuFORMHELP[""];
if (help) eval(help);
}
function nuSetLabelText(id, text, translate) {
if (translate) {
text = nuTranslate(text);
}
let obj = $('#' + id);
if (obj.is('label')) {
id = id.slice(6); // Remove 'label_' prefix
obj = $('#' + id);
}
const label = $('#label_' + id);
const left = obj.nuCSSNumber('left');
const top = obj.nuCSSNumber('top');
let visibleText = text;
if (/<[a-z][\s\S]*>/i.test(text)) {
const tmp = document.createElement('div');
tmp.innerHTML = text;
visibleText = tmp.textContent || tmp.innerText || '';
}
// Use the same font styling as the label or fallback to obj
const lwidth = nuGetWordWidth(visibleText, label.length ? label : obj);
label.css({
'top': top,
'left': left - lwidth - 17,
'width': lwidth + 12
}).html(text);
if (obj.attr('data-nu-label-position') === 'top') {
obj.nuLabelOnTop();
} else if (obj.attr('data-nu-label-position') === 'custom') {
nuCallWindowFunction("nuOnLabelPositionCustom", id);
}
}
function nuRunBackup() {
if (!nuGlobalAccess()) return;
if (confirm(nuTranslate("Perform the Backup now?"))) {
nuMessage(`${nuTranslate('Information')}`, `${nuTranslate('Backup is running')}` + "...");
nuRunPHPHidden("nu_backup");
}
}
function nuAddCSSStyle(styleString, id = 'nucssstyle') {
let existingStyle = document.getElementById(id);
if (existingStyle) existingStyle.remove();
styleString = styleString.replace(/( |<([^>]+)>)/ig, "").trim();
if (styleString === '') return;
const css = document.createElement('style');
css.id = id;
css.appendChild(document.createTextNode(styleString));
document.head.appendChild(css);
}
function nuAddStyleFromArray(id, obj) {
var arr = JSON.parse(obj.style);
for (let key in arr) {
if (Object.prototype.hasOwnProperty.call(arr, key)) {
let obj2;
if (key == 'label') {
obj2 = $('#' + 'label' + '_' + id);
} else {
obj2 = $('#' + id + ' .' + key);
if (obj2.length === 0) {
obj2 = $('#' + id);
}
}
if (obj.style_type == 'CSS') {
let css = obj2[0].getAttribute("style");
css = css === null ? arr[key] : css += ';' + arr[key];
obj2[0].setAttribute("style", css);
} else if (obj.style_type == 'Class') {
nuAddRemoveClasses(obj2, arr[key]);
}
}
}
}
function nuAddRemoveClasses($id, style) {
const classes = style.split(/\s+/).filter(Boolean);
classes.forEach(className => {
if (className.startsWith('-')) {
$id.removeClass(className.substring(1));
} else {
$id.addClass(className);
}
});
}
function nuAddStyle(id, obj) {
const $id = $('#' + id);
if (obj.style_type !== '' && obj.style !== '') {
if (obj.style_type == 'CSS') {
if (obj.style.startsWith('{')) {
nuAddStyleFromArray(id, obj);
} else {
let css = $id[0].getAttribute("style");
css = css === null ? obj.style : css + obj.style;
$id[0].setAttribute("style", css);
}
} else if (obj.style_type == 'Class') {
if (obj.style.startsWith('{')) {
nuAddStyleFromArray(id, obj);
} else {
nuAddRemoveClasses($id, obj.style);
}
}
}
}
function nuObjectClassList(id) {
const element = $('#' + id);
const classList = element.attr('class');
return classList ? classList.trim().split(/\s+/).join(' ') : '';
}
function nuGetStorageItem(key, storageType = 'session') {
const storage = storageType === 'session' ? window.sessionStorage : window.localStorage;
const itemStr = storage.getItem(key);
if (!itemStr) {
return null;
}
const item = JSON.parse(itemStr);
const now = new Date();
if (item.expiry !== null && now.getTime() > item.expiry) {
storage.removeItem(key);
return null;
}
return item.value;
}
function nuSetStorageItem(key, value, storageType = 'session', ttl = undefined) {
const storage = storageType === 'session' ? window.sessionStorage : window.localStorage;
const now = new Date();
const item = {
value: value
, expiry: ttl === undefined ? null : now.getTime() + ttl * 1000
,
};
storage.setItem(key, JSON.stringify(item));
}
function nuCtrlCmdShiftName(keyName) {
if (keyName === '') return '';
const modifier = nuIsMacintosh() ? 'Cmd' : 'Ctrl';
return modifier + '+Shift+' + keyName;
}
function nuDateIsValid(date) {
return (
Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date)
);
}
function nuObjectIdIsValid(id) {
if (typeof id !== 'string' || id.length === 0) {
return false;
}
const validIdPattern = /^[^\d\s][^\s]*$/u;
return validIdPattern.test(id);
}
function nuEscapeHTML(string, extraReplacements = {}) {
if (typeof string !== 'string') return '';
const baseReplacements = {
'<': '<',
'>': '>',
'&': '&',
'"': '"',
"'": ''',
'`': '`',
'\\': '\'
};
const replacements = {
...baseReplacements,
...extraReplacements
};
const pattern = new RegExp(`[${Object.keys(replacements).map(c => '\\' + c).join('')}]`, 'g');
return string.replace(pattern, character => replacements[character]);
}
function nuDelay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function nuInsertAtCaret(id, string) {
const txt = $('#' + id);
const caretPos = txt[0].selectionStart;
const value = txt.val();
txt.val(value.substring(0, caretPos) + string + value.substring(caretPos));
txt.nuSetFocus();
const endOfText = caretPos + string.length;
txt.prop('selectionStart', endOfText);
txt.prop('selectionEnd', endOfText);
}
function nuComposeURL(url, text, target = '_blank', protocol = '', title = '') {
if (!url || typeof url !== 'string' || url.trim() === '') {
return text;
}
url = url.trim();
protocol = protocol.trim();
title = title.trim();
if (protocol === 'mailto:' || protocol === 'tel:') {
return `${text}`;
}
return `${text}`;
}
function nuGetURLParameterValue(parameterName) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(parameterName);
}
function nuSetURLPermaLink() {
const prop = nuCurrentProperties();
if (window.top === window.self) {
let home = nuGetURLParameterValue('h') || '';
home = home ? '&h=' + home : '';
const urlParams = `?f=${prop.form_id}&r=${prop.record_id}${home}`;
const urlContainsI = window.location.search.includes('?i=');
const historyMethod = urlContainsI ? 'replaceState' : 'pushState';
window.history[historyMethod]('', document.title, urlParams);
}
}
function nuShuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i],
arr[j]] = [arr[j],
arr[i]];
}
}
function nuCharacterArray(symbols = true, numbers = true, lowerAlpha = true, upperAlpha = true) {
const characterSets = {
lowerAlpha: 'abcdefghijklmnopqrstuvwxyz',
upperAlpha: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
numbers: '0123456789',
symbols: '!@#%&*()-_+={}[]|:;<>.?'
};
let characters = [];
if (symbols) characters.push(...characterSets.symbols);
if (numbers) characters.push(...characterSets.numbers);
if (lowerAlpha) characters.push(...characterSets.lowerAlpha);
if (upperAlpha) characters.push(...characterSets.upperAlpha);
return characters;
}
function nuRandomPassword(characterArray, size) {
let shuffled = characterArray.slice();
nuShuffleArray(shuffled);
return shuffled.slice(0, size).join("");
}
function nuMonthArray(options = { month: 'long' }, locale = 'en-US') {
const arr = [];
for (let i = 0; i < 12; i++) {
const date = new Date(Date.UTC(2000, i, 1));
const item = date.toLocaleString(locale, options);
arr.push(item);
}
return arr;
}
function nuEventName(eventName = null) {
if (!eventName) {
eventName = nuRecordId().slice(-2);
}
const ev = [];
ev.BB = 'Before Browse';
ev.BE = 'Before Edit';
ev.BS = 'Before Save';
ev.AS = 'After Save';
ev.BD = 'Before Delete';
ev.AD = 'After Delete';
ev.AB = 'After Browse';
return ev[eventName];
}
function nuConsoleErrorsToMessage(cancel = false) {
if (cancel) {
window.onerror = () => true;
return;
}
if (window.onerror) return;
window.onerror = function (msg, url, lineNo, columnNo, error) {
const msgDevConsole = nuTranslate('Please check the browser developer console for details.');
if (msg == "ResizeObserver loop limit exceeded")
return; // ignore
if (msg.toLowerCase().indexOf('script error') > -1) {
nuMessage(nuTranslate('JavaScript Error'), msgDevConsole);
} else {
const message = [
msg,
'',
msgDevConsole
];
nuMessage(nuTranslate('JavaScript Error'), message);
}
return false;
};
}
function nuSetAttributes(element, attributes) {
for (const key in attributes) {
if (Object.prototype.hasOwnProperty.call(attributes, key)) {
element.setAttribute(key, attributes[key]);
}
}
}
function nuGetWindowProperty(key, property) {
if (!window[key]) {
return undefined;
}
if (property === undefined) {
return window[key];
}
if (window[key][property] !== undefined) {
return window[key][property];
}
return undefined;
}
function nuDestroyWindowProperty(key, property) {
if (!window[key]) {
return;
}
if (property !== undefined) {
if (window[key].hasOwnProperty(property)) {
if (typeof window[key][property].destroy === 'function') {
window[key][property].destroy();
}
delete window[key][property];
}
} else {
for (let prop in window[key]) {
if (window[key].hasOwnProperty(prop)) {
if (typeof window[key][prop].destroy === 'function') {
window[key][prop].destroy();
}
delete window[key][prop];
}
}
}
}
function nuSetWindowProperty(key, property, value) {
if (!window[key]) {
window[key] = {};
}
if (value !== undefined) {
window[key][property] = value;
}
}
function nuCallWindowFunction(fnName, ...args) {
const obj = args.length && typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Element)
? args.shift()
: window;
const fn = obj?.[fnName];
if (typeof fn === 'function') {
return fn(...args);
}
return undefined;
}
function nuCountDefinedArguments(...args) {
return args.filter(arg => arg !== undefined).length;
}
function nuToggleStyleAttribute(id, attributes) {
const el = document.getElementById(id);
if (!el) {
console.error(`Element with id "${id}" not found.`);
return;
}
let isModified = attributes.some(attr => el.hasAttribute(attr.dataAttr));
if (isModified) {
attributes.forEach(attr => {
const originalValue = el.getAttribute(attr.dataAttr);
if (originalValue !== null) {
el.style[attr.styleProp] = originalValue;
el.removeAttribute(attr.dataAttr);
}
});
} else {
attributes.forEach(attr => {
el.setAttribute(attr.dataAttr, el.style[attr.styleProp] || '');
if (attr.value !== null) {
el.style[attr.styleProp] = typeof attr.value === 'number' ? `${attr.value}px` : attr.value;
}
});
}
}
function nuToggleSize(id, height = null, width = null) {
nuToggleStyleAttribute(id, [
{ styleProp: 'height', dataAttr: 'data-nu-org-height', value: height },
{ styleProp: 'width', dataAttr: 'data-nu-org-width', value: width }
]);
}
function nuTogglePosition(id, top = null, left = null) {
nuToggleStyleAttribute(id, [
{ styleProp: 'top', dataAttr: 'data-nu-org-top', value: top },
{ styleProp: 'left', dataAttr: 'data-nu-org-left', value: left }
]);
}
function nuGetSelectedText(inputOrId) {
const input = typeof inputOrId === 'string'
? document.getElementById(inputOrId)
: inputOrId;
if (!input || typeof input.selectionStart !== 'number') {
return '';
}
const start = input.selectionStart;
const end = input.selectionEnd;
return input.value.substring(start, end);
}
// Info Bar jQuery Plugin
(function ($) {
'use strict';
// Plugin defaults
const defaults = {
// Content and styling
html: ' This is an info message',
type: 'info', // info, success, warning, error
theme: 'light', // light, dark
icon: null, // Font Awesome icon class (overrides default type icon)
customClass: null, // Additional CSS class to apply
// Behavior
autoClose: true,
autoCloseDelay: 5000, // 5 seconds
showCloseButton: true,
allowMultiple: false,
hideOnFormClose: true, // Hide info bar when form closes
shakeOnShow: false, // Shake the info bar when it's shown
modal: false, // If true, blocks clicks outside and shakes on outside clicks
// Animation
animationDuration: 300,
animationType: 'slide', // slide, fade
slideDirection: 'down', // down, up
// Shake animation
shakeDuration: 500, // Duration of shake animation in ms
shakeIntensity: 5, // Shake distance in pixels
// Positioning
position: 'top', // top, bottom
fixed: true, // if true, positions fixed at viewport top and pushes content down
zIndex: 10000, // increased to ensure it appears above nuBuilder elements
// Styling
opacity: 1, // custom opacity (0-1)
closeOnClick: false, // close when clicking anywhere on the bar (not just X button)
// Callbacks
onShow: null,
onClose: null,
onClick: null,
onShake: null // Called when shake animation completes
};
// Add CSS animations for shake effect and modal styles
const shakeCSS = `
@keyframes nu-info-bar-horizontal-shake {
0% { transform: translateX(0) }
25% { transform: translateX(var(--shake-intensity, 5px)) }
50% { transform: translateX(calc(-1 * var(--shake-intensity, 5px))) }
75% { transform: translateX(var(--shake-intensity, 5px)) }
100% { transform: translateX(0) }
}
@keyframes nu-info-bar-vertical-shake {
0% { transform: translateY(0) }
25% { transform: translateY(var(--shake-intensity, 5px)) }
50% { transform: translateY(calc(-1 * var(--shake-intensity, 5px))) }
75% { transform: translateY(var(--shake-intensity, 5px)) }
100% { transform: translateY(0) }
}
.nu-info-bar--shaking-horizontal {
animation: nu-info-bar-horizontal-shake var(--shake-duration, 500ms) ease-in-out;
}
.nu-info-bar--shaking-vertical {
animation: nu-info-bar-vertical-shake var(--shake-duration, 500ms) ease-in-out;
}
.nu-info-bar--modal {
box-shadow: 0 0 0 99999px rgba(0, 0, 0, 0.3);
position: relative;
}
.nu-info-bar--modal::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.1);
z-index: -1;
pointer-events: none;
}
`;
// Inject CSS if not already present
if (!$('#nu-info-bar-shake-styles').length) {
$('head').append(``);
}
// Main plugin function
$.fn.nuInfoBar = function (options) {
// Handle modal defaults
if (options && options.modal && !options.hasOwnProperty('autoClose')) {
options.autoClose = false;
}
const settings = $.extend({}, defaults, options);
return this.each(function () {
const $container = $(this);
// Create and show the info bar
createInfoBar($container, settings);
});
};
// Static method to show info bar on nuBuilder
$.nuInfoBar = function (options) {
// Handle modal defaults
if (options && options.modal && !options.hasOwnProperty('autoClose')) {
options.autoClose = false;
}
const $nuhtml = $('#nuhtml');
if ($nuhtml.length === 0) {
console.warn('nuBuilder container (#nuhtml) not found');
return;
}
return $nuhtml.nuInfoBar(options);
};
// Static method to show info bar on nuBuilder with fixed positioning
$.nuInfoBar.fixed = function (options) {
return $.nuInfoBar($.extend({}, options, { fixed: true }));
};
// Static methods for different types
function createTypedInfoBar(type, defaultIcon, message, options) {
options = options || {};
const icon = options.icon || defaultIcon;
const finalHtml = ` ${message}`;
const finalOptions = $.extend({}, options, {
html: finalHtml,
type: type
});
// Handle modal defaults
if (finalOptions.modal && !options.hasOwnProperty('autoClose')) {
finalOptions.autoClose = false;
}
return $.nuInfoBar(finalOptions);
}
$.nuInfoBar.info = function (message, options) {
return createTypedInfoBar('info', 'fas fa-info-circle', message, options);
};
$.nuInfoBar.success = function (message, options) {
return createTypedInfoBar('success', 'fas fa-check-circle', message, options);
};
$.nuInfoBar.warning = function (message, options) {
return createTypedInfoBar('warning', 'fas fa-exclamation-triangle', message, options);
};
$.nuInfoBar.error = function (message, options) {
return createTypedInfoBar('error', 'fas fa-times-circle', message, options);
};
// Shake functionality
$.nuInfoBar.shake = function (options) {
const shakeSettings = $.extend({}, {
direction: 'horizontal', // horizontal, vertical
duration: 500,
intensity: 5,
selector: '.nu-info-bar', // Target specific info bars
onComplete: null
}, options);
const $targetBars = $(shakeSettings.selector);
if ($targetBars.length === 0) {
console.warn('No info bars found to shake');
return;
}
$targetBars.each(function () {
const $bar = $(this);
shakeInfoBar($bar, shakeSettings);
});
return $targetBars;
};
// Shake the most recent info bar
$.nuInfoBar.shakeLast = function (options) {
const $lastBar = $('.nu-info-bar').last();
if ($lastBar.length === 0) {
console.warn('No info bars found to shake');
return;
}
const shakeSettings = $.extend({}, {
direction: 'horizontal',
duration: 500,
intensity: 5,
onComplete: null
}, options);
shakeInfoBar($lastBar, shakeSettings);
return $lastBar;
};
// Utility functions
$.nuInfoBar.updateContent = function (newHtml) {
$('.nu-info-bar .nu-info-bar__content').html(newHtml);
};
$.nuInfoBar.closeAll = function (options) {
// Default close options
const closeDefaults = {
animationType: 'slide',
animationDuration: 300,
position: 'top',
fixed: true,
modal: false // Default for cleanup
};
// Merge with provided options
const closeSettings = $.extend({}, closeDefaults, options);
$('.nu-info-bar').each(function () {
const $bar = $(this);
// Check if this bar is modal and clean up accordingly
const isModal = $bar.hasClass('nu-info-bar--modal');
const barSettings = $.extend({}, closeSettings, { modal: isModal });
// Trigger close with appropriate settings
closeInfoBar($bar, barSettings);
});
// Reset all padding immediately after closing all bars
const $target = $('#nuhtml').length > 0 ? $('#nuhtml') : $('body');
$target.css({
'padding-top': '0px',
'padding-bottom': '0px'
});
};
// Modal info bar shortcuts
$.nuInfoBar.modal = function (options) {
return $.nuInfoBar($.extend({}, options, { modal: true }));
};
$.nuInfoBar.modal.info = function (message, options) {
return createTypedInfoBar('info', 'fas fa-info-circle', message, $.extend({}, options, { modal: true }));
};
$.nuInfoBar.modal.success = function (message, options) {
return createTypedInfoBar('success', 'fas fa-check-circle', message, $.extend({}, options, { modal: true }));
};
$.nuInfoBar.modal.warning = function (message, options) {
return createTypedInfoBar('warning', 'fas fa-exclamation-triangle', message, $.extend({}, options, { modal: true }));
};
$.nuInfoBar.modal.error = function (message, options) {
return createTypedInfoBar('error', 'fas fa-times-circle', message, $.extend({}, options, { modal: true }));
};
// Shake an info bar
function shakeInfoBar($infoBar, settings) {
// Set CSS custom properties for animation
$infoBar.css({
'--shake-duration': settings.duration + 'ms',
'--shake-intensity': settings.intensity + 'px'
});
// Remove any existing shake classes
$infoBar.removeClass('nu-info-bar--shaking-horizontal nu-info-bar--shaking-vertical');
// Add appropriate shake class
const shakeClass = settings.direction === 'vertical' ?
'nu-info-bar--shaking-vertical' : 'nu-info-bar--shaking-horizontal';
$infoBar.addClass(shakeClass);
// Remove shake class after animation completes
setTimeout(function () {
$infoBar.removeClass(shakeClass);
if (settings.onComplete) {
settings.onComplete.call($infoBar[0]);
}
}, settings.duration);
}
// Create and manage info bar
function createInfoBar($container, settings) {
// Set global hideOnFormClose variable
window.nuInfoBarHideOnFormClose = settings.hideOnFormClose;
// Remove existing bars if not allowing multiple
if (!settings.allowMultiple) {
const $existingBars = $('.nu-info-bar');
const hasFixedBars = $existingBars.filter(function () {
return $(this).css('position') === 'fixed';
}).length > 0;
$existingBars.remove();
// Reset padding if removing fixed bars
if (hasFixedBars) {
// For nuBuilder, reset padding on #nuhtml if it exists, otherwise body
const $target = $('#nuhtml').length > 0 ? $('#nuhtml') : $('body');
$target.css({
'padding-top': '0px',
'padding-bottom': '0px'
});
}
}
// Create info bar element
let classes = `nu-info-bar nu-info-bar--${settings.type} nu-info-bar--${settings.theme}`;
if (settings.customClass) {
classes += ` ${settings.customClass}`;
}
if (settings.closeOnClick) {
classes += ` nu-info-bar--clickable`;
}
if (settings.modal) {
classes += ` nu-info-bar--modal`;
}
const $infoBar = $('', {
class: classes,
css: {
position: settings.fixed ? 'fixed' : 'absolute',
top: settings.position === 'top' ? 0 : 'auto',
bottom: settings.position === 'bottom' ? 0 : 'auto',
left: 0,
right: 0,
zIndex: settings.zIndex,
opacity: settings.opacity,
display: 'none'
}
});
// Create close button if enabled
if (settings.showCloseButton) {
const $closeBtn = $('