wb/mgr/model/columns/MixinPropMgrColumn.js

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

/**
 * @module nmodule/webEditors/rc/wb/mgr/model/columns/MixinPropMgrColumn
 */
define([ 'baja!',
        'underscore',
        'nmodule/webEditors/rc/fe/baja/util/facetsUtils',
        'nmodule/webEditors/rc/fe/baja/util/typeUtils',
        'nmodule/webEditors/rc/wb/mgr/model/MgrColumn' ], function (
         baja,
         _,
         facetsUtils,
         typeUtils,
         MgrColumn) {

  'use strict';

  var toProperties = facetsUtils.toProperties,
      getSlotDisplayName = typeUtils.getSlotDisplayName,
      getSlotFacets = typeUtils.getSlotFacets;

  function toSlotName(type) {
    return String(type).replace(':', '_');
  }

  function toColumnName(type, prop) {
    return toSlotName(type) + '_' + prop;
  }

  /**
   * API Status: **Development**
   *
   * MgrColumn that allows you to edit a property on a `baja:IMixIn` installed
   * on a component.
   *
   * @class
   * @alias module:nmodule/webEditors/rc/wb/mgr/model/columns/MixinPropMgrColumn
   * @extends module:nmodule/webEditors/rc/wb/mgr/model/MgrColumn
   * @param {Type} type the `BIMixIn` Type whose property you wish to edit
   * @param {String|baja.Slot} prop the property 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, or if prop is not a frozen
   * slot on the given Type
   */
  var MixinPropMgrColumn = function MixinPropMgrColumn(type, prop, params) {
    MgrColumn.call(this, toColumnName(type, prop), _.extend({
      displayName: getSlotDisplayName(type, prop)
    }, params));
    this.$type = type;
    this.$prop = prop;
  };
  MixinPropMgrColumn.prototype = Object.create(MgrColumn.prototype);
  MixinPropMgrColumn.prototype.constructor = MixinPropMgrColumn;

  /**
   * Get the mixin instance from the component loaded into the row.
   *
   * @private
   * @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
   * @returns {baja.Value|null}
   */
  MixinPropMgrColumn.prototype.$getMixinInstance = function (row) {
    var comp = row.getSubject();

    return comp.get(toSlotName(this.$type));
  };

  /**
   * When creating an editor for this column, use the value coalesced from the
   * given rows, and respect any slot Facets on the mixin Type.
   *
   * @param {Array.<module:nmodule/webEditors/rc/wb/table/model/Row>} rows
   * @returns {Object} config with value and facets
   */
  MixinPropMgrColumn.prototype.getConfigFor = function (rows) {
    return {
      value: this.coalesceRows(rows),
      properties: toProperties(getSlotFacets(this.$type, this.$prop))
    };
  };

  /**
   * 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}
   */
  MixinPropMgrColumn.prototype.getValueFor = function (row) {
    var instance = this.$getMixinInstance(row);

    if (!instance) {
      instance = baja.$(this.$type);
    }

    return instance.get(this.$prop);
  };

  //TODO: this seems unsafe - if we edit two instances at once, could we wind up double-adding the mixin?
  //but if it doesn't have the mixin it's probably unmounted, and therefore the add operation will be sync

  /**
   * 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.
   *
   * @param {baja.Value} value
   * @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
   * @param {Object} [params]
   * @returns {Promise}
   */
  MixinPropMgrColumn.prototype.commit = function (value, row, params) {
    var instance = this.$getMixinInstance(row),
        type = this.$type,
        prop = this.$prop,
        batch = params && params.batch,
        progressCallback = params && params.progressCallback,
        prom;

    function commitReady() {
      if (progressCallback) { progressCallback(MgrColumn.COMMIT_READY); }
    }

    if (instance) {
      prom = instance.set({ slot: prop, value: value, batch: batch });
      commitReady();
      return prom;
    } else {
      instance = baja.$(type);
      return instance.set({ slot: prop, value: value })
        .then(function () {
          prom = row.getSubject().add({
            slot: toSlotName(type),
            value: instance,
            batch: batch
          });
          commitReady();
          return prom;
        });
    }

  };

  return (MixinPropMgrColumn);
});