/** * Created by rburson on 3/18/16. */ import * as React from 'react' import { CvAction, CvState, CvProps, CvBaseMixin, CvListPane, CvRecordList, CvNavigationResult, CvEvent, CvRecord, CvContext, CvQueryPaneCallback, CvValueListener, CvValueAdapter, CvStateChangeResult, CvActionFiredResult, CvActionCallback, CvValueProvider, CvActionHandlerParams, CvNavigation, CvForm, CvSearchPane, CvSearchPaneCallback, CvSortDirection } from 'catreact' import { CvDataAnno, CvDataAnnoStyle, CvHtmlProp } from './catreact-html' import {FormContext, ListContext, Prop, ColumnDef, EntityRec} from 'catavolt-sdk' export interface CvListPanelState extends CvState { selectedItems:Array; searchNavResult:CvNavigationResult; } export interface CvListPanelProps extends CvProps { paneRef?:number; formContext?:FormContext; listContext?:ListContext; navigationListeners?:Array<(event:CvEvent)=>void>; actionListeners?:Array<(event:CvEvent)=>void> selectionListener?:CvValueListener>; stateChangeListeners?:Array<(event:CvEvent)=>void>; actionProvider?:CvValueProvider; searchable?:boolean; } /* *************************************************** * Render a ListContext *************************************************** */ export var CvListPanel = React.createClass({ mixins: [CvBaseMixin], getDefaultProps: function () { return { paneRef: null, formContext: null, listContext: null, navigationListeners: [], selectionListener: null, stateChangeListeners: [], actionProvider:null, searchable:false, } }, getInitialState: function () { return {selectedItems: [], searchNavResult:null} }, render: function () { /* We can't do ES7 style rest destructuring in Typescript yet... */ const listPaneProps = { paneRef: this.props.paneRef, formContext: this.props.formContext, queryContext: this.props.listContext, stateChangeListeners: this.props.stateChangeListeners, actionListeners: this.props.actionListeners, actionProvider: this.props.actionProvider } return ( { const listContext:ListContext = cvContext.scopeCtx.scopeObj; return(
{(()=>{ return this.props.searchable ? {}} paneContext={listContext} navigationListeners={[(event:CvEvent)=>{ this.setState({searchNavResult: event.eventObj}); }]}/> : null; })()}
{(()=>{ return this.props.searchable ? { return }}/> : null; })()}
{ return ( { const rowProps = this._isSelected(record.objectId) ? {className: 'cv-selected-row'} : {}; rowProps['onClick'] = this._itemClicked.bind(this, record.objectId); return ( {listContext.listDef.activeColumnDefs.map((columnDef:ColumnDef)=> { const name:string = columnDef.name; //select "this record" so that the action can find the target via the selectionProvider const selectionAdapter:CvValueAdapter> = new CvValueAdapter>(); selectionAdapter.createValueListener()([record.objectId]); const prop:Prop = record.propAtName(name); return ( { const styleInfo:CvDataAnnoStyle = (CvDataAnno as any).generateStyleInfo(prop); const cellStyle = 'cv-list-cell cv-target ' + CvListColumnHeader.classForColumnDef(columnDef); return( { e.preventDefault(); e.stopPropagation(); callback.fireAction()} }} overrideValue={styleInfo.overrideText}/> ); }}/> ) })} ); }}/> ); }}/>
{/* //The following is an example of using paging controls, rather then infintite scrolling //The style should be changed in the above pane, to remove the scrollbar, for this example work nicely //When using the 'true' value for the replaceBuffer flag with the below paging methods, the list is updated //to reflect only the current page in the buffer
{(()=>{ if(callback.hasMoreBackward()){ return ( );}})()}
{(()=>{ if(callback.hasMoreForward()){ return ( );}})()}
*/}
); }}/> ); }, _isSelected: function (oid:string) { return this.state.selectedItems.indexOf(oid) > -1; }, _itemClicked: function (oid:string) { const selectedItems:Array = this.state.selectedItems; const index = selectedItems.indexOf(oid); if (index > -1) { selectedItems.splice(index, 1); } else { selectedItems.push(oid); } this.setState({selectedItems: selectedItems}); if (this.props.selectionListener) this.props.selectionListener(selectedItems); }, _magicScroll: function (callback:CvQueryPaneCallback, e:any) { var elem:any = e.currentTarget; if (elem.scrollTop / (elem.scrollHeight - elem.clientHeight) > .95) { if(callback.hasMoreForward()) { callback.pageForward((num)=> { }); } } }, }); export var CvListTableHeader = React.createClass<{searchNavResult:CvNavigationResult, listContext:ListContext},{}>({ getDefaultProps: function () { return {searchNavResult: null, listContext: null} }, render: function () { const {searchNavResult, listContext} = this.props; return ( {searchNavResult ? ( { return {[].concat(listContext.listDef.activeColumnDefs.map((colDef, i) => { return }))} }}/> ) : ( {[].concat(listContext.listDef.activeColumnDefs.map((colDef, index) => { return {colDef.heading} }))} ) } ); } }); export var CvListColumnHeader = React.createClass<{colDef:ColumnDef, searchCallback:CvSearchPaneCallback},{}>({ getDefaultProps: function () { return {colDef: null, searchCallback: null} }, render: function () { const {colDef, searchCallback} = this.props; const dir = searchCallback.getSortValueDirection(colDef.name); //server may return ASCENDING or ASC and DSC or DESCENDING const nextDir = this._isAsc(dir) ? 'DSC' : 'ASC'; //size the cell let sizeClass = ' ' + CvListColumnHeader.classForColumnDef(colDef); return { searchCallback.reopenSearch((success, error)=>{ searchCallback.clearSortValues(); searchCallback.setSortValue(colName, nextDir, 0); searchCallback.submitSearch((success, error)=>{}); }) }).bind(this, colDef.name)}> {colDef.heading} {(()=>{ if(dir) { const className = this._isAsc(dir) ? "glyphicon glyphicon-triangle-top cv-sort-dir" : "glyphicon glyphicon-triangle-bottom cv-sort-dir"; return