Files
Fuchs_Intranet/Fuchs/js/intranet/fis_main.js
T
2026-09-10 21:17:35 +02:00

363 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$ocms.init = function (ev) {
var mdl = typeof ev === 'string' ? ev : ((ev.data || {}).fn || '');
if (mdl === '') {
return;
} else if (mdl === 'home') {
$cfr(); $lfr();
$('#topbar').ocmsmenu([], true);
$('#activemodule').text($t.ov);
$fis.ov();
} else {
$cfr(); $lfr();
$('#topbar').ocmsmenu([]);
$ocms.postXT({
url: $ocms.url(mdl + '/auth'), success: function (auth) {
if (typeof $ocms[mdl] === 'undefined') {
$ocms[mdl] = {};
}
$ocms[mdl].auth = auth;
if (auth.manage > 0) {
/* ?v=<assetversion> (newest bundle write time, emitted by _Layout) busts the browser
cache of the dynamically imported module bundle + css after a gulp rebuild. */
let av = '?v=' + encodeURIComponent($ocms.auth.assetversion || '0');
$ocms.getScript({
module: mdl, script: ['/web/fis', mdl, $ocms.auth.locale || 'de', 'js'].join('.') + av, css: ['/web/fis', mdl, 'css'].join('.') + av, condition: typeof $ocms[mdl].init2 !== 'function'
}, function () { $ocms[mdl].init2(); });
}
}, error: function () {
$('#contentframe').empty();
}
});
}
};
var $fis = { auth: {} };
$fis.db = function () {
$('#mainmenu_activemodule').text($t.ov);
let cf = $(this).empty(), ovf = $$.d({ id: 'dashboard_frame' }).appendTo(cf);
$ocms.postXT({
url: $ocms.url('wdg/my'), success: function (wx) {
$.each(wx, function (ii, wi) {
var wf = $$.dc('wdg_frame', ovf, { 'data-wdg': wi }).hide();
$ocms.wdg.call(wf, { wdg: wi });
});
}, loading: ovf
});
};
$fis.ValidateEmail = function (mail) {
if (/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(mail)) {
return true;
} else {
return false;
}
};
$fis.cf = (reset) => {
let cf = $('#contentframe'); if (bool(reset, false) === true) { cf.empty().rC('hd'); } return cf;
}
$fis.lf = (reset) => {
let lf = $('#listframe'); if (bool(reset, false) === true) { lf.empty().aC('hd').rC('fix'); } return lf;
};
$fis.frm_edit = function (resethd) {
let cf = $fis.cf(false), cf2 = cf.children('.cfrm'), edf = cf.children('.edit_frm');
if (cf2.length < 1) {
cf2 = $$.dc('cfrm hd').prependTo(cf);
} else if (bool(resethd, false) === true) {
cf2.empty();
}
if (edf.length < 1) {
edf = $$.dc('edit_frm').insertAfter(cf2); //must be before list
}
return edf.empty();
};
$fis.frm_list = function (resethd, remedit) {
let cf = $fis.cf(false), cf2 = cf.children('.cfrm'), lf = cf.children('.list_frm');
if (cf2.length < 1) {
cf2 = $$.dc('cfrm hd').prependTo(cf);
} else if (bool(resethd, false) === true) {
cf2.empty();
}
if (bool(remedit, false) === true) {
cf.children('.edit_frm').remove();
}
if (lf.length < 1) {
lf = $$.dc('list_frm').appendTo(cf); //must be after list
}
return lf.empty();
};
$fis.lfm = () => {
let lf = $fis.lf(false) , h = lf.children('.lfrm');
if (h.length < 1) {
h = $$.dc('lfrm').prependTo(lf);
}
return h;
};
$fis.getAuth = (module, force) => {
return new Promise((resolve, reject) => {
if ($fis.auth[module] && bool(force, false) === false) {
resolve($fis.auth[module] || -1);
} else {
$ocms.postXT({
url: $ocms.url('auth'), data: { module: module }, success: (response) => {
$fis.auth[module] = response.auth || -1;
resolve($fis.auth[module] || -1);
}, error: () => {
reject();
}
});
}
});
};
$fis.prepAuth = (modules) => {
return new Promise((resolve, reject) => {
$ocms.postXT({
url: $ocms.url('auth'), data: { module: modules, array: 1 }, success: (response) => {
$.extend($fis.auth, response || {});
}, complete: () => {
resolve();
}
});
});
};
$fis.isAuth = (module, min) => {
return ($fis.auth[module] || -1) >= (min || 1);
};
$fis.resetPass = function (id, fds) {
if (confirm($t.smsc)) {
$ocms.postXT({ url: $ocms.url('account/sms'), data: { fn: 'pwc'} });
$ocms.dlgform($fd.rsp.clone(), {
title: $t.rsp || '',
submit: function (e) {
var c = $(this).ldng(1);
var qs = $.extend({ loginaccount: $ocms.auth.account || '' }, c.serializeObject(true, { typedvalues: true }));
if ((qs.npw || '') !== (qs.npwc || '')) {
c.find('input[name="npw"]:first')[0].setCustomValidity($t.pnm);
} else {
$ocms.postXT({
url: $ocms.url('account/changepassword'), data: qs, success: function (response) {
alert($t.cps);
c.trigger('modal_close');
}, error: function (x) {
alert($t.rspf[x.getResponseHeader('x-ocms-std')]);
}, complete: function () {
c.ldng(0);
}, timeout: 60000
});
}
}
});
}
};
$fis.wdg = function (options) {
let wf = $(this).empty();
$ocms.postXT({
url: $ocms.url('wdg/one'), data: { short_name: options.wdg }, timeout: 90000, success: function (response, textStatus, jqXHR) {
let wi = options.wdg, wx = response[wi];
if (!wx) { wf.ldng(0); return; }
let dbl = $.inArrayRegEx('dblwidth', wx.rendering_options) > -1, tiny = $.inArrayRegEx('tiny', wx.rendering_options) > -1;
wf.toggleClass('dbl', dbl && !tiny).toggleClass('tny', tiny);
let whd = $$.dc('wdg_hd', wf, { title: ne(wx.description, $t.wdc) }).toggleClass('dbl', dbl).text(ne(wx.name, options.wdg)).dblclick(function (ev) {
ev.stopPropagation();
$fis.wdg.call(wf, { wdg: wi });
});
let wct = $$.dc('wdg_cnt', wf).toggleClass('dbl', dbl).hide();
let bgcolix = $.inArrayRegEx('bgcolor', wx.rendering_options);
if (bgcolix > -1) { wct.css('backgroundColor', wx.rendering_options[bgcolix].toString().right(':')); }
switch (wx.type) {
case 'table':
var tblset = $$.tblset({}, wct);
var thr = $$.tr().appendTo(tblset.hd);
var $cc = $t.wdg[wi.indexOf('wdg_ev_') >= 0 ? 'wdg_ev_' : wi] || {};
$.each(wx.columns, function (ci, col) {
var cc = (!$cc[col]) ? col : $cc[col].label;
var thc = $$.th().text(cc).appendTo(thr);
});
$.each(wx.data, function (di, dx) {
var tdr = $$.tr().appendTo(tblset.bdy);
$.each(wx.columns, function (ci, col) {
var tdc = $$.td().appendTo(tdr);
if (dx[col] instanceof Date || $ocms.isJSONDateString(dx[col]) === true) {
tdc.text(fdt(dx[col], $t.dateformat));
} else {
tdc.rwText(dx[col]);
}
});
//if (dx.person_guid || false) { tdr.addClass('clickable').dblclick($.proxy($fis.i_vmm, tdr, dx.person_guid[1])); }
});
if ($.inArray('firstrow_bold', wx.rendering_options) > -1) { thr.nextAll('tr:first').css('font-weight', 'bold'); }
break;
case 'ind':
$$.dc('ind', wct).addClass('sts_' + (wx.data.status || '')).append([$$.dc('ind').text(wx.data.value), $$.lbl(wx.data.label)]);
break;
case 'image_url':
wct.css('background', 'url(\'' + wx.url + '\') no-repeat center center transparent');
break;
case 'image_base64':
wct.css('background', 'url(\'data:image/png;base64,' + wx.image + '\') no-repeat center center transparent');
break;
case 'html':
wct.html(wx.html);
if ($.inArray('reload_10min', wx.rendering_options) > -1) {
var ifr = wct.find('iframe');
setTimeout(function () { ifr.attr('src', function (i, val) { return val; }); }, (10 * 60 * 1000));
}
break;
default:
}
if ($.inArray('reload_30min', wx.rendering_options) > -1 && wx.type !== 'html') {
setTimeout(function () { $fis.wdg.call(wf, { wdg: wi }); }, (30 * 60 * 1000));
}
if (wf.is(':visible')) {
wct.slideDown(150);
} else {
wct.show();
wf.fadeIn(150);
}
}, error: function (jqXHR) {
if (wf.is(':visible')) { wf.slideUp(150); }
$fis.failure.call(this, jqXHR);
}, complete: function () {
wf.ldng(0).trigger('wdg:settled');
}
});
};
$fis.ov = function () {
//$('#mainmenu_activemodule').text("");
$fis.lf(true);
let cf = $('#contentframe').empty(), ovf = $$.d({ id: 'dashboard_frame' }).appendTo(cf);
$ocms.postXT({
url: $ocms.url('wdg/my'), success: function (wx) {
let ind = $$.dc('wdg_loading_ind', ovf).text($t.wldg || '').hide();
let pending = wx.length;
let settle = function () {
if (--pending <= 0) { ind.fadeOut(150); }
};
if (pending > 0) { ind.show(); }
$.each(wx, function (ii, wi) {
var wf = $$.dc('wdg_frame', ovf, { 'data-wdg': wi }).hide().one('wdg:settled', settle);
$fis.wdg.call(wf, { wdg: wi });
});
}, loading: ovf
});
};
$fis.notifications = {
connection: null,
init: function () {
if (typeof signalR === 'undefined' || this.connection !== null || !$ocms.auth.useraccount_id) {
return;
}
this.ensureFrame();
this.connection = new signalR.HubConnectionBuilder()
.withUrl('/notifications')
.withAutomaticReconnect()
.build();
this.connection.on('notification', (notification) => {
this.push(notification);
});
// withAutomaticReconnect() only retries a connection that was successfully
// established and later dropped — it does not retry a failed initial start()
// (e.g. the server restarting mid-debug). Without this, a single failed start()
// silently blackholes every notification for the rest of the page's lifetime.
this.connection.onclose(() => {
console.warn('Notification connection closed; retrying in 5s.');
this.connection = null;
setTimeout(() => this.init(), 5000);
});
this.start();
},
start: function () {
this.connection.start().catch((err) => {
console.warn('Notification connection failed to start; retrying in 5s.', err);
this.connection = null;
setTimeout(() => this.init(), 5000);
});
},
ensureFrame: function () {
if ($('#notification_frame').length < 1) {
$('<div/>', { id: 'notification_frame' }).appendTo($('footer:first').length ? 'footer:first' : 'body');
}
},
push: function (notification) {
this.ensureFrame();
notification = notification || {};
let item = $('<div/>', { class: 'notification_item' })
.addClass((notification.severity || 'info').toLowerCase())
.append($('<button/>', { type: 'button', class: 'notification_close', text: '×' }))
.append($('<div/>', { class: 'notification_title', text: notification.title || 'Info' }))
.append($('<div/>', { class: 'notification_message', text: notification.message || '' }));
item.find('.notification_close').on('click', function () {
item.remove();
});
$('#notification_frame').prepend(item);
setTimeout(function () {
item.fadeOut(150, function () { item.remove(); });
}, 9000);
}
};
/* Live draft-editing client (ADR 0006/0007). Separate SignalR connection to the
dedicated /draftpreview hub; the server signals the *one* browser editing a draft
(group = session token) to re-fetch (draftReady), warns before idle expiry
(draftExpiring), and tells it to close on eviction (draftClosed). The editor
(fis.inv_shared.js) registers the open draft via $fis.draft.bind(token, {...}). */
$fis.draft = {
connection: null,
active: null, /* { token, onReady(version), onExpiring(secondsLeft), onClosed(reason) } */
init: function () {
if (typeof signalR === 'undefined' || this.connection !== null || !$ocms.auth.useraccount_id) {
return;
}
this.connection = new signalR.HubConnectionBuilder()
.withUrl('/draftpreview')
.withAutomaticReconnect()
.build();
this.connection.on('draftReady', (p) => this._dispatch('onReady', p, (p) => p.version));
this.connection.on('draftExpiring', (p) => this._dispatch('onExpiring', p, (p) => p.secondsLeft));
this.connection.on('draftClosed', (p) => this._dispatch('onClosed', p, (p) => p.reason));
/* Re-join the active draft's group after a (re)connect — group membership is
per-connection and is lost when the socket drops. */
this.connection.onreconnected(() => { if (this.active) { this._invoke('JoinDraft', this.active.token); } });
this.connection.onclose(() => {
console.warn('Draft connection closed; retrying in 5s.');
this.connection = null;
setTimeout(() => { this.init(); if (this.active) { this.bind(this.active.token, this.active); } }, 5000);
});
this.start();
},
start: function () {
this.connection.start()
.then(() => { if (this.active) { this._invoke('JoinDraft', this.active.token); } })
.catch((err) => {
console.warn('Draft connection failed to start; retrying in 5s.', err);
this.connection = null;
setTimeout(() => this.init(), 5000);
});
},
/* Registers the currently open draft and joins its signal group. handlers:
{ onReady, onExpiring, onClosed }. */
bind: function (token, handlers) {
if (!token) { return; }
this.active = $.extend({ token: token }, handlers || {});
if (this.connection === null) { this.init(); }
this._invoke('JoinDraft', token);
},
/* Unregisters + leaves the group (editor closed). */
release: function (token) {
if (this.active && (!token || this.active.token === token)) { this.active = null; }
this._invoke('LeaveDraft', token);
},
_invoke: function (method, token) {
if (!token || !this.connection || this.connection.state !== 'Connected') { return; }
this.connection.invoke(method, token).catch((err) => console.warn('Draft ' + method + ' failed', err));
},
_dispatch: function (handler, payload, argOf) {
payload = payload || {};
if (!this.active || this.active.token !== payload.token) { return; }
if (typeof this.active[handler] === 'function') { this.active[handler](argOf(payload)); }
}
};