UNPKG

@universis/dining

Version:

Universis api for dining

215 lines (210 loc) 7.43 kB
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 }