Reference Source

js/rendering/table.js

// NPM IMPORTS
import h from 'virtual-dom/h'

// COMMON IMPORTS
import T                   from '../utils/types'
import rendering_normalize from './rendering_normalize'
import uid                 from '../utils/uid'


let context = 'common/rendering/table'



// DEFAULT STATE
const default_state = {
	label:undefined,
	headers:undefined,  // array (rows) of array (th values)
	items:undefined,    // array (rows) of array (cells)
	footers:undefined   // array (rows) of array (th values)
}

// DEFAULT SETTINGS
const default_settings = {
	class:undefined,
	style:undefined,
	id:undefined
}



/**
 * Table rendering with given state, produce a rendering result.
 * 
 * @param {object} arg_settings - rendering item settings.
 * @param {object} arg_state - component state.
 * @param {object} arg_rendering_context - rendering context: { trace_fn:..., resolver:..., credentials:..., rendering_factory:... }.
 * @param {RenderingResult} arg_rendering_result - rendering result to update.
 * 
 * @returns {RenderingResult} - updated Rendering result: VNode or Html text, headers.
 */
export default (arg_settings, arg_state={}, arg_rendering_context, arg_rendering_result)=>{

	// DEBUG
	// console.log(context + ':rendering_function:arg_settings=', arg_settings)
	// console.log(context + ':rendering_function:arg_state=', arg_state)

	// NORMALIZE ARGS
	const { settings, state, rendering_context, rendering_result } = rendering_normalize(default_settings, default_state, arg_settings, arg_state, arg_rendering_context, arg_rendering_result, context)
	const rendering_factory = rendering_context ? rendering_context.rendering_factory : undefined
	
	// GET STATE ATTRIBUTES
	const label_value   = T.isString(state.label)  ? state.label : undefined
	const headers_value = T.isArray(state.headers) ? (label_value ? [[label_value]].concat(state.headers) : state.headers) : (label_value ? [[label_value]] : undefined)
	const items_value   = T.isArray(state.items)   ? state.items : undefined
	const footers_value = T.isArray(state.footers) ? state.footers : undefined

	// GET SETTINGS ATTRIBUTES
	const has_body_cursor = T.isBoolean(settings.has_body_cursor) ? settings.has_body_cursor : undefined

	// DEBUG
	rendering_context.trace_fn(state.headers, context + ':state.headers')
	rendering_context.trace_fn(state.items, context + ':state.items')
	rendering_context.trace_fn(headers_value, context + ':headers_value')
	rendering_context.trace_fn(items_value, context + ':items_value')

	// BUILD THEAD, TBODY, TFOOT
	const cell_fn = (cell) =>{
		return T.isFunction(rendering_factory) ? rendering_factory(cell, rendering_context, settings.children).get_final_vtree(undefined, rendering_result) : cell.toString()
	}
	const cell_content=(tag, cell_settings, index)=>{
		// CELL CONTENT SETTINGS IS AN OBJECT
		if ( T.isObject(cell_settings) )
		{
			// CELL CONTENT IS A VALUE
			if ( ! T.isString(cell_settings.type) && T.isString(cell_settings.value) )
			{
				if ( ! T.isString(cell_settings.key) )
				{
					cell_settings.key = uid()
				}
				
				return h(tag, { id:settings.id + '_' + cell_settings.key }, [ cell_settings.value ])
			}

			// CELL CONTENT IS A VIEW
			if ( ! T.isString(cell_settings.type) && T.isString(cell_settings.view) )
			{
				if ( ! T.isString(cell_settings.key) )
				{
					cell_settings.key = cell_settings.view
				}

				return h(tag, { id:settings.id + '_' + cell_settings.key }, [ cell_fn(cell_settings.view) ] )
			}

			// CELL IS A RENDERING SETTINGS
			if ( T.isString(cell_settings.type) )
			{
				return h(tag, { id:settings.id + '_' + tag + '_' + index }, [ cell_fn(cell_settings) ] )
			}

			const str_value = cell_settings.toString()
			return h(tag, { id:settings.id + '_' + tag + '_' + index }, [ str_value ] )
		}
		
		const str_value = T.isString(cell_settings) ? cell_settings : ( T.isFunction(cell_settings.toString) ? cell_settings.toString() : 'ERROR')
		return h(tag, { id:settings.id + '_' + tag + '_' + index }, [ str_value ] )
	}
	const th_fn = (content, index)=>cell_content('th', content, index)
	const td_fn = (content, index)=>cell_content('td', content, index)

	const tr_th_fn = (cells, index)  =>h('tr', { id:settings.id + '_head_row_' + index }, (T.isArray(cells) ? cells : [cells]).map(th_fn) )
	const tr_td_fn = (cells, index)  =>h('tr', { id:settings.id + '_body_row_' + index }, (T.isArray(cells) ? cells : [cells]).map(td_fn) )
	const tr_tf_fn = (cells, index)  =>h('tr', { id:settings.id + '_foot_row_' + index }, (T.isArray(cells) ? cells : [cells]).map(th_fn) )
	
	const thead_children = headers_value ? (T.isArray(headers_value) ? headers_value : [headers_value]).map(tr_th_fn) : undefined
	const tbody_children = items_value   ? (T.isArray(items_value)   ? items_value   : [items_value]).map(tr_td_fn)   : undefined
	const tfoot_children = footers_value ? (T.isArray(footers_value) ? footers_value : [footers_value]).map(tr_tf_fn) : undefined

	const thead_props = undefined
	const tbody_props = has_body_cursor ? { style:"cursor:pointer;" } : undefined
	const tfoot_props = undefined

	const thead = h('thead', thead_props, thead_children)
	const tbody = h('tbody', tbody_props, tbody_children)
	const tfoot = h('tfoot', tfoot_props, tfoot_children)

	// BUILD TAG
	const tag_id = settings.id
	const tag_children = [thead, tbody, tfoot]
	const tag_props = { id:tag_id, style:settings.style, className:settings.class }
	const tag = h('table', tag_props, tag_children)

	// DEBUG
	// console.log(context + ':rendering_function:settings=', settings)
	// console.log(context + ':rendering_function:tag_props=', tag_props)

	rendering_result.add_vtree(tag_id, tag)

	return rendering_result
}