/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Logan Byam
*/
/**
* @module nmodule/webEditors/rc/wb/table/model/Column
*/
define([ 'Promise',
'nmodule/js/rc/tinyevents/tinyevents',
'nmodule/webEditors/rc/mixin/DataMixin' ], function (
Promise,
tinyevents,
DataMixin) {
'use strict';
function setFlag(col, flag, isSet) {
var flags = col.$flags;
col.setFlags(isSet ? flags | flag : flags & ~flag);
}
/**
* API Status: **Development**
*
* Column for use in a `TableModel`.
*
* As of Niagara 4.8, arbitrary data can be stored on a Column instance. To
* enable tables and table exporters to use a context object when formatting
* table cells, add a `context` value.
*
* @class
* @alias module:nmodule/webEditors/rc/wb/table/model/Column
* @mixes tinyevents
* @mixes module:nmodule/webEditors/rc/mixin/DataMixin
* @param {String} [name] column name
* @param {Object} [params]
* @param {String} [params.displayName] column display name; `name` will be
* used if omitted. This should not contain HTML as any HTML will be escaped.
* @param {Number} [params.flags] column flags
* @see module:nmodule/webEditors/rc/wb/table/model/TableModel
* @example
* <caption>Append context data for formatting use in tables and table
* exporters.</caption>
* const myBooleanColumn = new Column('myBoolean');
* myBooleanColumn.data('context', { trueText: 'Yes!', falseText: 'No!' });
*/
var Column = function Column(name, params) {
params = params || {};
this.$name = name ? String(name) : null;
this.$displayName = params.displayName;
this.$flags = params.flags || 0;
this.$sortable = true;
this.$hidable = true;
this.$exportable = true;
tinyevents(this);
DataMixin(this);
};
/**
* Available configuration flags for a Column.
* @type {Object}
*/
Column.flags = {
/**
* This column's value should be shown in an editor.
*/
EDITABLE: 0x0001,
/**
* This column should not be shown by default, but only visible if
* explicitly shown by the user.
*/
UNSEEN: 0x0002,
/**
* This column is intended to be shown in an editor, but readonly.
*/
READONLY: 0x0004
};
/**
* Get the column name or `null` if none was given.
*
* @returns {String}
*/
Column.prototype.getName = function () {
return this.$name;
};
/**
* Resolves a display name for this column.
*
* @returns {Promise|*} promise to be resolved when the element's display name
* has been fully built. It's also acceptable for overrides of this function
* to complete synchronously without returning a promise, so be sure to wrap
* calls to this function in `Promise.resolve()` when appropriate.
*/
Column.prototype.toDisplayName = function () {
return Promise.resolve(this.$displayName || this.getName());
};
/**
* Builds out the DOM element, typically a `td`, that represents the
* intersection of this column with a particular row. Often this will simply
* be a simple `toString()` or similar, but could also do more sophisticated
* things like build widgets.
*
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @param {JQuery} dom
* @returns {Promise|*} promise to be resolved when the element's contents
* have been fully built. It's also acceptable for overrides of this function
* to complete synchronously without returning a promise, so be sure to wrap
* calls to this function in `Promise.resolve()` when appropriate.
*/
Column.prototype.buildCell = function (row, dom) {
const value = this.getValueFor(row);
const context = this.$getContext(row);
const str = (value === null || value === undefined || !context) ? String(value) : value.toString(context);
return Promise.resolve(str)
.then((text) => dom.text(text));
};
/**
* @private
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row the row we're building the cell for
* @returns {*} context object for formatting the value in this row for display. Override for
* specialized behavior. Return a falsy value to use synchronous, non-localized formatting.
*/
Column.prototype.$getContext = function (row) {
return this.data('context');
};
/**
* Called when the table is destroying the DOM element built for a cell in this column. This
* gives a `Column` implementation the chance to clean up any resources that might have been
* created during the earlier call to `#buildCell`, perhaps destroying a widget in the cell,
* for example. As with `#buildCell`, if this completes synchronously and doesn't return a
* Promise, the caller must wrap this in a call to `Promise.resolve()`.
*
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @param {JQuery} dom
* @returns {Promise|*}
*/
Column.prototype.destroyCell = function (row, dom) {
return Promise.resolve();
};
/**
* Returns a URI for an icon representing this column. Returns `null` by
* default; override as needed in subclasses.
*
* @returns {String} a URI for an icon to be shown for this column.
*/
Column.prototype.getColumnIcon = function () {
return null;
};
/**
* Get the flags set on this column.
*
* @returns {Number}
*/
Column.prototype.getFlags = function () {
return this.$flags;
};
/**
* Return true if the column has *all* of the given flags.
*
* @param {Number} flags flags to check for
* @returns {Boolean}
*/
Column.prototype.hasFlags = function (flags) {
return (this.$flags & flags) === flags;
};
/**
* Set the column's flags.
*
* @param {Number} flags
* @throws {Error} if a non-Number given
*/
Column.prototype.setFlags = function (flags) {
if (typeof flags !== 'number') {
throw new Error('number required');
}
this.$flags = flags;
this.emit('flagsChanged', flags);
};
/**
* Override point; each column should define its own method of retrieving a
* value from the given table row.
*
* @abstract
* @param {module:nmodule/webEditors/rc/wb/table/model/Row} row
* @returns {*} the row value. Note that this is synchronous; if the row's
* subject is not ready to provide a value, it should not be loaded into the
* table.
* @throws {Error} if not implemented
*/
Column.prototype.getValueFor = function (row) {
throw new Error('#getValueFor() not implemented');
};
/**
* Return true if the column is editable.
*
* @returns {Boolean}
*/
Column.prototype.isEditable = function () {
return this.hasFlags(Column.flags.EDITABLE);
};
/**
* Set or unset the column's `EDITABLE` flag. Emits a `flagsChanged` event.
*
* @param {boolean} editable
*/
Column.prototype.setEditable = function (editable) {
setFlag(this, Column.flags.EDITABLE, editable);
};
/**
* Return true if the column is readonly.
*
* @returns {Boolean}
*/
Column.prototype.isReadonly = function () {
return this.hasFlags(Column.flags.READONLY);
};
/**
* Set or unset the column's `READONLY` flag. Emits a `flagsChanged` event.
*
* @param {boolean} readonly
*/
Column.prototype.setReadonly = function (readonly) {
setFlag(this, Column.flags.READONLY, readonly);
};
/**
* Return true if the column is unseen.
*
* @returns {Boolean}
*/
Column.prototype.isUnseen = function () {
return this.hasFlags(Column.flags.UNSEEN);
};
/**
* Set or unset the column's `UNSEEN` flag. Emits a `flagsChanged` event.
*
* @param {boolean} unseen
*/
Column.prototype.setUnseen = function (unseen) {
setFlag(this, Column.flags.UNSEEN, unseen);
};
/**
* Returns a boolean indicating whether the column should not be sortable via the table headings.
* Defaults to true.
*
* @returns {Boolean}
*/
Column.prototype.isSortable = function () {
return this.$sortable;
};
/**
* Set or unset whether the column should be allowed to be sorted by the table heading.
* @param {boolean} sortable
*/
Column.prototype.setSortable = function (sortable) {
this.$sortable = !!sortable;
};
/**
* Return true if the column should available in the table's show/hide context menu.
* Defaults to true.
*
* @returns {Boolean}
*/
Column.prototype.isHidable = function () {
return this.$hidable;
};
/**
* Set or unset whether the column should be allowed to be hidden or shown by the table's
* show/hide context menu.
*
* @param {boolean} hidable
*/
Column.prototype.setHidable = function (hidable) {
this.$hidable = !!hidable;
};
/**
* Return true if the column should show up in export operations, e.g. to CSV.
* @returns {Boolean}
* @since Niagara 4.8
*/
Column.prototype.isExportable = function () {
return this.$exportable;
};
/**
* Set or unset whether the column should show up in export operations.
*
* @param {boolean} exportable
* @since Niagara 4.8
*/
Column.prototype.setExportable = function (exportable) {
this.$exportable = !!exportable;
};
return Column;
});