@universis/dining
Version:
Universis api for dining
215 lines (210 loc) • 7.43 kB
JavaScript
import {Args} from '@themost/common';
import {ElotConverter} from '@universis/elot-converter';
/**
* @name DataContext#locale
* @description Gets or sets the current context locale
* @type {string}
*/
/**
* Returns true if a data model has a localization enabled
* @param {DataModel} model
* @returns {DataField}
*/
function hasLocales(model) {
Args.notNull(model, 'model');
const attribute = model.getAttribute('locales');
// if target model does not have a `locales` attribute
if (attribute == null) {
return null;
}
// if attribute belongs to another model (and it's being inherited by this model)
if (attribute.model !== model.name) {
return null;
}
return attribute;
}
function getElotAttributes(context) {
// do not require elotAttributes configuration
// make it completely optional
return context.getConfiguration().getSourceAt('settings/i18n/elotAttributes') || ['familyName', 'givenName', 'motherName', 'fatherName'];
}
function getElotLocale() {
return {
requiresDefault: 'el',
isInLocale: 'en'
}
}
/**
* @param {DataEventArgs} event
* @returns {Promise<void>}
*/
async function afterSaveAsync(event) {
const context = event.model.context;
const attribute = hasLocales(event.model);
if (attribute == null) {
// do nothing
return;
}
if (Object.prototype.hasOwnProperty.call(event.target, 'locales') === false) {
// do nothing and exit because locales property is missing
return;
}
// get localized model
const childModel = context.model(attribute.type);
// throw error for invalid model
if (childModel == null) {
throw new Error('Invalid configuration. Localization model cannot be found or is not inaccessible yet');
}
if (Array.isArray(event.target.locales) === false) {
throw new Error('Invalid property type. Property locales must be an array');
}
for (let i = 0; i < event.target.locales.length; i++) {
const itemLocale = event.target.locales[i];
if (childModel.sealed === false) {
// delete primary key if any
delete itemLocale[childModel.primaryKey];
}
if (itemLocale.object == null) {
// set object key
Object.defineProperty(itemLocale, 'object', {
configurable: true,
enumerable: true,
writable: true,
value: event.target[event.model.primaryKey]
});
}
}
if (childModel.sealed === true) {
// if child model (locale model) is sealed add only other language (not default)
// get default application locale
let defaultLocale = context.getConfiguration().getSourceAt('settings/i18n/defaultLocale');
// throw error if default locale is not defined
if (defaultLocale == null) {
throw new Error('Invalid application configuration. The default locale is missing.');
}
event.target.locales = event.target.locales.filter((item) => {
return item.inLanguage !== defaultLocale;
});
}
// important note: get silent mode of parent model
const silentMode = event.model.isSilent();
// apply silent mode and save items
if (event.target.locales.length > 0) {
await childModel.silent(silentMode).save(event.target.locales);
}
}
/**
* @param {DataEventArgs} event
* @returns {Promise<void>}
*/
async function beforeSaveAsync(event) {
const context = event.model.context;
const attribute = hasLocales(event.model);
if (attribute == null) {
// do nothing
return;
}
// get localized model
const childModel = context.model(attribute.type);
// ensure locales property
event.target.locales = event.target.locales || [];
// get default application locale
let defaultLocale = context.getConfiguration().getSourceAt('settings/i18n/defaultLocale');
// throw error if default locale is not defined
if (defaultLocale == null) {
throw new Error('Invalid application configuration. The default locale is missing.');
}
let findLocale = event.target.locales.find((item) => {
return item.inLanguage === defaultLocale;
});
let add = false;
if (findLocale == null) {
add = true;
findLocale = {};
}
// enumerate properties and update object
childModel.attributes.forEach((attribute) => {
if (!attribute.primary && attribute.type !== event.model.name) {
if (Object.prototype.hasOwnProperty.call(event.target, attribute.name)) {
Object.defineProperty(findLocale, attribute.name, {
configurable: true,
enumerable: true,
writable: true,
value: event.target[attribute.name]
});
}
}
});
// set language
findLocale.inLanguage = defaultLocale;
if (add) {
event.target.locales.push(findLocale);
}
if (defaultLocale === getElotLocale().requiresDefault) {
// try to find locale that is in language of elot locale
let elotLocale = event.target.locales.find(locale => locale.inLanguage === getElotLocale().isInLocale);
let addElotLocale = false;
if (!elotLocale) {
elotLocale = {};
addElotLocale = true;
}
// get elot attributes
const elotAttributes = getElotAttributes(context);
// if they are configured, validate them
if (!(Array.isArray(elotAttributes) && elotAttributes.length)) {
throw new Error('Invalid configuration. Elot attributes must be a (not-empty) array, e.g. ["familyName", "givenName"]');
}
// get previous state
// it can be undefined for various reasons (e.g. insert state, missing or misplaced previous-state-listener)
const previous = event.previous;
// enumerate elot attributes
for (const attribute of elotAttributes) {
// if target has the property
if (Object.prototype.hasOwnProperty.call(event.target, attribute)) {
// it's not null and has been changed
if (event.target[attribute] != null && event.target[attribute] != (previous && previous[attribute])) {
// convert and assign to elot locale
elotLocale[attribute] = ElotConverter.convert(event.target[attribute]);
}
}
}
if (addElotLocale) {
elotLocale.inLanguage = getElotLocale().isInLocale;
// and finally push the contructed locale
event.target.locales.push(elotLocale);
}
}
}
// noinspection JSUnusedGlobalSymbols
/**
*
* @param {DataEventArgs} event
* @param {*} callback
* @returns {any}
*/
function beforeSave(event, callback) {
return beforeSaveAsync(event).then(() => {
return callback();
}).catch((err) => {
return callback(err);
});
}
// noinspection JSUnusedGlobalSymbols
/**
*
* @param {DataEventArgs} event
* @param {*} callback
* @returns {any}
*/
function afterSave(event, callback) {
return afterSaveAsync(event).then(() => {
return callback();
}).catch((err) => {
return callback(err);
});
}
export {
hasLocales,
beforeSave,
afterSave
}