/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Logan Byam
*/
/**
* @module nmodule/webEditors/rc/wb/mgr/model/columns/MixinPropMgrColumn
*/
define([ 'baja!',
'Promise',
'underscore',
'nmodule/js/rc/switchboard/switchboard',
'nmodule/webEditors/rc/fe/baja/util/typeUtils',
'nmodule/webEditors/rc/wb/mgr/model/MgrColumn',
'nmodule/webEditors/rc/wb/mgr/model/columns/PropertyPathMgrColumn' ], function (
baja,
Promise,
_,
switchboard,
typeUtils,
MgrColumn,
PropertyPathMgrColumn) {
'use strict';
const { getPropValueFromPath } = PropertyPathMgrColumn;
const { isComplex } = typeUtils;
/**
* commitToNewInstance uses switchboard to ensure that a MixinPropMgrColumn won't attempt to add the
* same mixin instance more than once when there is more than one `MixinPropMgrColumn`
* registered on the same type.
* @type {Function}
*/
const ensureMixinInstanceExists = switchboard((column, row) => {
return column.$ensureMixinInstanceExists(row);
}, {
allow: 'oneAtATime',
keyedOn: function (column) { return column.$mixinType; }
});
function toSlotName(type) {
return String(type).replace(':', '_');
}
function toColumnName(type, path) {
return toSlotName(type) + '_' + path.join('_');
}
function defaultDisplayName(type, path) {
const complex = getPropValueFromPath(baja.$(type), _.initial(path));
return complex ? complex.getDisplayName(_.last(path)) : _.last(path);
}
/**
* Create a slash delimited path string from the array of path elements.
*/
function toPathString(path) {
return '/' + path.join('/');
}
/**
* API Status: **Development**
*
* MgrColumn that allows you to edit a property on a `baja:IMixIn` installed
* on a component.
*
* The property may also be several levels deep relative to the row's subject
* component's mixin.
*
* @class
* @alias module:nmodule/webEditors/rc/wb/mgr/model/columns/MixinPropMgrColumn
* @extends module:nmodule/webEditors/rc/wb/mgr/model/MgrColumn
* @param {string} name column name (if omitted, one will be generated). This
* was added in Niagara 4.13, but may be omitted (you may still use mixinType
* as the first parameter).
* @param {Type} mixinType the `BIMixIn` Type whose property you wish to edit
* @param {String|baja.Slot} path the property or property path (as a
* '/'-delimited string) you wish to edit.
* @param {Object} [params]
* @param {String} [params.displayName] the display name for the column;
* if omitted, will use the slot display name from the Type
* @throws {Error} if Type or prop are missing
*/
class MixinPropMgrColumn extends PropertyPathMgrColumn {
constructor(name, mixinType, path, params) {
if (typeof name !== 'string') {
[ mixinType, path, params ] = arguments;
path = path.toString().split('/');
name = toColumnName(mixinType, path);
} else {
path = path.toString().split('/');
}
if (!mixinType || !_.isFunction(mixinType.is) || !mixinType.is('baja:IMixIn')) {
throw new Error('mixinType parameter must be a baja:IMixIn');
}
super(name, path.join('/'), _.extend({
displayName: defaultDisplayName(mixinType, path),
type: mixinType
}, params));
this.$mixinType = mixinType;
const commit = this.commit;
this.commit = function (value, row) {
return ensureMixinInstanceExists(this, row)
.then(() => commit.apply(this, arguments));
};
}
/**
* @private
* @return {String}
*/
$getMixInSlotName() {
return toSlotName(this.$mixinType);
}
/**
* Get the existing mixin instance that already belongs to the component
* loaded into the row. If called from `commit()`, the instance is
* guaranteed to have been added if it did not already exist.
*
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {baja.Value|null}
*/
getMixinInstance(row) {
return this.getMixinContainer(row).get(this.$getMixInSlotName());
}
/**
* Get the container where the mixin is located or will be located once it is added.
*
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {baja.Complex}
* @since Niagara 4.13
*/
getMixinContainer(row) {
return row.getSubject();
}
/**
* Get the mixin instance belonging to the component loaded into the row,
* or create a new instance to work with.
*
* @private
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {baja.Value}
*/
$getOrMakeMixinInstance(row) {
return this.getMixinInstance(row) || baja.$(this.$mixinType);
}
/**
* Get the complex this property is on. Utilize the existing mixin instance or
* create a new instance of the mixIn if it does not exist yet.
*
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {baja.Complex}
*/
getComplexFromPath(row) {
return PropertyPathMgrColumn.getPropValueFromPath(this.$getOrMakeMixinInstance(row), _.initial(this.$path));
}
/**
* Get the property from the mixin instance on this row's component. If
* the component does not have an instance of that mixin (e.g. it is an
* unmounted component created browser-side), the default value from an
* instance of that mixin will be returned.
*
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {baja.Value}
*/
getValueFor(row) {
const instance = this.$getOrMakeMixinInstance(row);
if (!isComplex(instance)) {
throw new Error('Complex required');
}
const prop = getPropValueFromPath(instance, this.$path);
if (prop !== null) { return prop; }
throw new Error('Could not get slot value for path: ' + toPathString(this.$path));
}
/**
* Sets the value to the mixin instance on the row's component. If the
* component does not have an instance of the mixin, a new one will be
* created.
*
* This method may be safely overridden while maintaining the assurance that
* the mixin instance exists.
*
* @param {baja.Value} value
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @param {Object} params
* @returns {Promise}
*/
commit(value, row, params) {
// mixin behavior is patched in in the constructor.
return super.commit(...arguments);
}
/**
* Sets the value to a new mixin instance for the row.
*
* @private
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {Promise}
*/
$ensureMixinInstanceExists(row) {
if (this.getMixinInstance(row)) {
return Promise.resolve();
}
const slot = this.$getMixInSlotName();
const comp = this.getMixinContainer(row);
const mixin = baja.$(this.$mixinType);
return comp.add({ slot, value: mixin });
}
}
return MixinPropMgrColumn;
});