wb/table/model/columns/PropertyColumn.js

/**
 * @copyright 2015 Tridium, Inc. All Rights Reserved.
 * @author Logan Byam
 */

/**
 * @module nmodule/webEditors/rc/wb/table/model/columns/PropertyColumn
 */
define([ 'baja!',
        'Promise',
        'underscore',
        'nmodule/webEditors/rc/fe/baja/util/typeUtils',
        'nmodule/webEditors/rc/wb/table/model/Column' ], function (
         baja,
         Promise,
         _,
         typeUtils,
         Column) {

  'use strict';

  var getSlotDisplayName = typeUtils.getSlotDisplayName,
      getSlotType = typeUtils.getSlotType,
      isComplex = typeUtils.isComplex;
  const { extend } = _;

  /**
   * API Status: **Development**
   *
   * Column for showing the value of a Complex's Property slot.
   *
   * @class
   * @alias module:nmodule/webEditors/rc/wb/table/model/columns/PropertyColumn
   * @extends module:nmodule/webEditors/rc/wb/table/model/Column
   * @param {String|baja.Slot} prop the property slot to read from a Complex
   * @param {Object} [params]
   * @param {Type} [params.type] if reading a frozen slot, pass in the Type
   * instance to be able to resolve the display name/facets for that frozen slot
   * @param {Function} [params.getDefaultValue] a function to provide a custom
   * default value for getValueFor to return if the row's Complex does not
   * have the column prop. The function will be passed the row's Complex.
   */
  var PropertyColumn = function PropertyColumn(prop, params) {
    var that = this;
    Column.apply(that, arguments);
    that.$prop = prop;
    that.$type = params && params.type;
    that.$getDefaultValue = params && params.getDefaultValue;
  };
  PropertyColumn.prototype = Object.create(Column.prototype);
  PropertyColumn.prototype.constructor = PropertyColumn;

  /**
   * Resolves the display name of the property slot.
   *
   * @returns {Promise} promise to be resolved with the display name
   */
  PropertyColumn.prototype.toDisplayName = function () {
    var prop = this.$prop,
        type = this.$type;

    return Promise.resolve(this.$displayName ||
      (type ? getSlotDisplayName(type, prop) : prop));
  };

  /**
   * Shows a display string of the desired property value of the row's
   * loaded Complex.
   *
   * @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
   * @param {JQuery} dom
   * @returns {Promise} resolves when the cell has been built
   */
  PropertyColumn.prototype.buildCell = function (row, dom) {
    let context = this.$getContext(row);
    const value = this.getValueFor(row);
    return Promise.resolve(context ? value.toString(context) : value.toString())
      .then(function (string) {
        dom.text(string);
      });
  };

  /**
   * @private
   * @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
   * @returns {*} the column's specified context, or the slot facets from this row if unspecified
   */
  PropertyColumn.prototype.$getContext = function (row) {
    const context = Column.prototype.$getContext.apply(this, arguments);
    if (context === null) {
      return undefined;
    }

    const complex = this.$getComplex(row);
    const propFacets = complex.getFacets(this.$prop);
    const facets = propFacets ? propFacets.toObject() : {};
    return extend(facets, context);
  };

  /**
   * If a `type` param was given, then return an icon for the given slot on
   * that type. Otherwise, return null.
   *
   * @returns {String}
   */
  PropertyColumn.prototype.getColumnIcon = function () {
    var prop = this.$prop,
        type = this.$type;

    if (type) {
      try {
        var slotType = getSlotType(type, prop);
        if (slotType) {
          return slotType.getIcon().getImageUris()[0];
        }
      } catch (ignore) {}
    }

    return null;
  };

  /**
   * Returns the Complex instance that this column should read its Property from. By default, this is presumed to be the row's subject itself
   * @since Niagara 4.14
   * @private
   * @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
   * @returns {baja.Complex}
   */
  PropertyColumn.prototype.$getComplex = function (row) {
    return row.getSubject();
  };

  /**
   * Get the value of the Property specified in the constructor from the row's
   * loaded Complex.
   *
   * If the Complex does not have that Property:
   *
   * If a `getDefaultValue` param was passed into this column's constructor, the
   * row's Complex will be passed into the function and the result will be
   * returned.
   *
   * If a `type` param was passed into this column's constructor, the value
   * of the property from the default instance of the given type will be
   * returned.
   *
   * @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
   * @returns {baja.Value} the Property value read from the Complex
   * @throws {Error} if the row does not actually have a Complex loaded, or
   * does not have the specified Property (and type is unknown)
   */
  PropertyColumn.prototype.getValueFor = function (row) {
    var comp = this.$getComplex(row),
        that = this,
        getDefaultValue = that.$getDefaultValue,
        prop = that.$prop,
        type = that.$type;

    if (!isComplex(comp)) {
      throw new Error('complex required');
    }

    if (comp.has(prop)) {
      return comp.get(prop);
    }

    if (getDefaultValue) {
      return getDefaultValue(comp);
    }

    if (type && comp.getType().is(type)) {
      return typeUtils.getSlotDefaultValue(type, prop);
    }

    throw new Error(
      'complex does not have property ' + prop +
      ' or getDefaultValue function given'
    );
  };

  return (PropertyColumn);
});