src/renderers/index.js
import {Map} from 'immutable';
import ViewType from '~/types/view';
/**
* Collection of render functions of a specific type (eg. React renderers).
*/
export default class Renderers {
/**
* Creates a new set of renderers for a set of types.
* @param {object.<string, Renderer>} renderers - The set of renderers for each ViewType registered.
*/
constructor(renderers) {
this.renderers = renderers || {};
this.cachedValues = Map();
}
/**
* Registers a new renderer for a specific type.
* @param {string} typeName - The name of the renderer to register.
* @param {Renderer} renderer - The renderer to register.
*/
register(typeName, renderer) {
this.renderers[typeName] = renderer;
}
bustCache(type, viewType, dataValue) {
const path = [type, viewType, dataValue];
this.cachedValues.deleteIn(path);
}
cache(type, viewType, dataValue, create) {
if (typeof viewType == 'string') {
const path = [type, viewType, dataValue];
this.cachedValues = this.cachedValues
.updateIn(path, cachedView => cachedView ?
cachedView :
create()
);
return this.cachedValues.getIn(path);
} else {
return create();
}
}
/**
* See {@link Renderer#renderFormField}
*/
renderFormField(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return this.renderers[viewType.constructor.typeName].renderFormField(viewType, renderData, this);
}
/**
* See {@link Renderer#renderStaticField}
*/
renderStaticField(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return this.renderers[viewType.constructor.typeName].renderStaticField(viewType, renderData, this);
}
/**
* See {@link Renderer#renderFormFilter}
*/
renderFormFilter(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return this.renderers[viewType.constructor.typeName].renderFormFilter(viewType, renderData, this);
}
/**
* See {@link Renderer#renderFilter}
*/
renderFilter(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return this.renderers[viewType.constructor.typeName].renderFilter(viewType, renderData, this);
}
/**
* See {@link Renderer#renderTableCell}
*/
renderTableCell(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return this.renderers[viewType.constructor.typeName].renderTableCell(viewType, renderData, this);
}
/**
* See {@link Renderer#renderStaticTableCell}
*/
renderStaticTableCell(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return this.renderers[viewType.constructor.typeName].renderStaticTableCell(viewType, renderData, this);
}
/**
* Initializes the view type to display with a specific set of data. This is
* normally to call the required API calls before the data is display.
* @params {ViewType} viewType - The view type to render.
* @params {RenderData} renderData - The data to render.
* @returns {Promise} - Resolved upon completion, rejected if error loading.
*/
initialize(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return viewType.initialize(renderData);
}
/**
* Returns the raw data value that is represented by this view type.
* @params {ViewType} viewType - The view type to render.
* @params {RenderData} renderData - The data to render.
*/
getValue(viewType, renderData) {
return this.cache('value', viewType, renderData.dataValue, () => {
viewType = this.parseViewType(viewType, renderData);
return viewType.getValue(renderData, this);
});
}
/**
* Returns a "pretty" data value that is represented by this view type.
* @params {ViewType} viewType - The view type to render.
* @params {RenderData} renderData - The data to render.
*/
getDisplay(viewType, renderData) {
return this.cache('display', viewType, renderData.dataValue, () => {
viewType = this.parseViewType(viewType, renderData);
return viewType.getDisplay(renderData, this);
});
}
/**
* Returns a map of properties to use to display a table.
* @params {ViewType} viewType - The view type to get the props of.
*/
getTableProps(viewType, renderData) {
viewType = this.parseViewType(viewType, renderData);
return viewType.getTableProps();
}
/**
* If the view type passed in is a string and if the `viewTypes` property
* exists in the renderData options, attempt to look up the viewType by name.
*/
parseViewType(viewType, renderData) {
const viewTypes = this.getViewTypes(renderData);
if (typeof viewType == 'string') {
const lookup = viewTypes.get(viewType);
if (lookup) {
return this.parseViewType(lookup, renderData);
}
} else if (viewType instanceof ViewType) {
return viewType;
}
throw new Error(`Invalid ViewType passed: ${viewType} (${viewTypes})`);
}
getViewTypes(renderData) {
const viewTypes = typeof renderData.options.viewTypes == 'function' ?
renderData.options.viewTypes(renderData) :
renderData.options.viewTypes;
return viewTypes || Map();
}
}
/**
* The renderers to use to render view types to js values.
*/
export const valueRenderers = new Renderers();