Options
All
  • Public
  • Public/Protected
  • All
Menu

External module "ext/CvGridPanel"

Created by rburson on 3/18/16.

Index

Variables

CV_GRID_PAGE_SIZE

CV_GRID_PAGE_SIZE: number = 100

CV_GRID_ROW_OVERFLOW_SIZE

CV_GRID_ROW_OVERFLOW_SIZE: 1 = 1

CV_GRID_SCROLL_BUFFER_ROWS

CV_GRID_SCROLL_BUFFER_ROWS: 30 = 30

CV_GRID_VISIBLE_ROWS

CV_GRID_VISIBLE_ROWS: 24 = 24

CvGridPanel

CvGridPanel: ClassicComponentClass<CvGridPanelProps> = React.createClass<CvGridPanelProps, CvGridPanelState>({mixins: [CvBaseMixin],componentWillMount: function() {//set up unmanaged, init valuesconst numInitialRows = this.props.numInitialRows ? this.props.numInitialRows : CV_GRID_PAGE_SIZE;this.setState({numInitialRows: numInitialRows});},componentDidMount: function () {/* Allow for copying cell content */new Clipboard('.cv-clipboard-target', {text: function (trigger) {return trigger.innerText;}});/*register to receive events from the 'popup search' editor modelthe list pane will refresh itself when the search is submitted but we needto reset the data source before that happens*/(this.eventRegistry() as CvEventRegistry).subscribe<CvStateChangeResult>(this._dataChangeListener, CvEventType.STATE_CHANGE);},componentWillUnmount: function() {(this.eventRegistry() as CvEventRegistry).unsubscribe(this._dataChangeListener);},componentWillReceiveProps(props, state) {//Log.debug('GridPanel will receive props:');//Log.debug(props);},componentWillUpdate(props, state) {//Log.debug('GridPanel will update: ');//Log.debug(props);},getDefaultProps: function () {return {paneRef: null,formContext: null,listContext: null,navigationListeners: [],actionListeners: [],gridListener: null,stateChangeListeners: [],actionProvider: null,searchable: false,initialSelectedItems: null,numInitialRows: CV_GRID_PAGE_SIZE,initialFirstVisibleRow: null}},getInitialState: function () {return {searchNavResult: null,quickFilterNavResult: null,complexSearchNavResult: null,numInitialRows: null,initialFirstVisibleRow: null}},render: function () {/* We can't do ES7 style rest destructuring in Typescript yet, so we do this... */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 (<CvListPane {...listPaneProps} recordPageSize={this.state.numInitialRows} queryRenderer={(cvContext:CvContext, callback:CvQueryPaneCallback)=>{const listContext:ListContext = cvContext.scopeCtx.scopeObj;return(<div className="cv-grid-container">{(()=>{return this.props.searchable ?<CvAction actionId={'#search'} fireOnLoad={(success, error)=>{}} paneContext={listContext}navigationListeners={[(event:CvEvent<CvNavigationResult>)=>{this.setState({searchNavResult: event.eventObj});}]}/> : null;})()}{(()=>{return this.props.searchable ?<CvAction actionId={'searchQuery'} fireOnLoad={(success, error)=>{}} paneContext={listContext}navigationListeners={[(event:CvEvent<CvNavigationResult>)=>{this.setState({quickFilterNavResult: event.eventObj});}]}/> : null;})()}<div className="text-right"><CvQuickFilter filterValueListener={(filterValue)=>{if(this.table){this.table.quickFilter(filterValue)} }}ref={(me)=>this.quickFilter=me}/><button className="btn btn-default" onClick={()=>{if(this.table){this.table.autoFit();}}} title="Fit To Table"><span className="glyphicon glyphicon-resize-full" aria-hidden="true"/></button><button className="btn btn-default" onClick={()=>{if(this.table){this.table.autoSize();}}} title="Autosize Columns"><span className="glyphicon glyphicon-text-width" aria-hidden="true"/></button><button className="btn btn-default" onClick={callback.refresh} title="Refresh All"><span className="glyphicon glyphicon-refresh" aria-hidden="true"/></button>{(()=>{/*This action fires a typical navigation which opens a search pane, which shows in a modal popup*/return this.props.searchable ?<CvAction actionId={'#search'}paneContext={listContext}navigationListeners={[(event:CvEvent<CvNavigationResult>)=>{this.setState({complexSearchNavResult: event.eventObj});}, ...this.props.navigationListeners]}actionListeners={this.props.actionListeners}stateChangeListeners={this.props.stateChangeListeners}renderer={(cvContext:CvContext, callback?:CvActionCallback)=>{return <button className="btn btn-default" onClick={()=>{if(this.quickFilter.isSet())this.quickFilter.resetText();callback.fireAction()}} title="Search"><span className="glyphicon glyphicon-search" aria-hidden="true"/></button>}}/> : null;})()}</div><div style={{width:'100%', height:'100%'}}>{(()=>{/* make sure that the search actions have been opened */return this._areSearchHandlesReady() ?<CvNavigation navigationResult={this.state.quickFilterNavResult}><CvForm formContext={this.state.quickFilterNavResult.navRequest}><CvSearchPane paneRef={0} initMode={CvInitMode.MANUAL} detailsRenderer={(cvContext:CvContext,entityRec:EntityRec, quickFilterCallback:CvSearchPaneCallback)=><CvGridTable listContext={listContext}lastRefreshTime={listContext.lastRefreshTime}initialSelectedItems={this.props.initialSelectedItems}numInitialRows={this.props.numInitialRows}initialFirstVisibleRow={this.props.initialFirstVisibleRow}queryPaneCallback={callback}searchNavResult={this.state.searchNavResult}quickFilterCallback={quickFilterCallback}eventRegistry={this.eventRegistry()}navigationListeners={this.props.navigationListeners}actionListeners={this.props.actionListeners}gridListener={this.props.gridListener}stateChangeListeners={this.props.stateChangeListeners}ref={table=>this.table = table}/>}/></CvForm></CvNavigation> : null;})()}</div></div>);}}/>);},shouldComponentUpdate(nextProps, nextState) {/*NOTE:initialSelectedItems, numInitialRows, initialFirstVisibleRow are all unmanaged properties, meaningthat when they change, they are not synchronized with component state (we ignore them)Here they are simply changing URL params to be retained only for navigation or a refresh*//*This is an 'exclusive' change list - updates happen by default unless included hereProps changes that should not fire updates, should be added here*///Don't update for selection changes as this is NOT a managed param//determine if this was a selection change//if so avoid a component updateconst initialSelectedItems = this.props.initialSelectedItems;const nextSelectedItems = nextProps.initialSelectedItems;//do we already have selected items//if so have we simply added or removed a selectionif(initialSelectedItems != null) {if (nextSelectedItems && (initialSelectedItems.length != nextSelectedItems.length)) {return false;}} else {//we don't have a selection but now, but having an incoming selectionif(nextSelectedItems != null) {return false;}}//Don't update for changes in original num rows//this is NOT a managed parameterif(nextProps.numInitialRows != this.props.numInitialRows) {return false;}//Don't update for changes in initialFirstVisibleRow//this is NOT a managed parameterif(nextProps.initialFirstVisibleRow != this.props.initialFirstVisibleRow) {return false;}//don't update if we are opening the search popoverif(nextState.complexSearchNavResult != this.state.complexSearchNavResult) {return false;}//otherwise we'll continue to update the grid...return true;},_dataChangeListener: function (dataChangeResult:CvEvent<CvStateChangeResult>) {const eventSource = dataChangeResult.eventObj.source;const eventType = dataChangeResult.eventObj.type;const complexSearchNavResult:CvNavigationResult = this.state.complexSearchNavResult;//listen for the modal search submissionif (eventType === CvStateChangeType.DATA_CHANGE) {if(eventSource && complexSearchNavResult && complexSearchNavResult.navRequest) {if (eventSource.parentContext == complexSearchNavResult.navRequest) {this.table.resetDataSource();}}}},_areSearchHandlesReady: function() {return this.state.quickFilterNavResult && this.state.searchNavResult;}})

CvGridPanel_DOT_REPL

CvGridPanel_DOT_REPL: "_d_o_t_" = "_d_o_t_"

CvGridTable

CvGridTable: ClassicComponentClass<CvGridTableProps> = React.createClass<CvGridTableProps,CvGridTableState>({autoSize: function () {const columns = this.columnApi.getAllColumns().filter(col=>col.visible).map(col=>col.colDef.field);this.columnApi.autoSizeColumns(columns);},autoFit: function () {this.gridApi.sizeColumnsToFit();},componentWillMount: function() {//set up unmanaged, init valuesconst numInitialRows = this.props.numInitialRows ? this.props.numInitialRows : CV_GRID_PAGE_SIZE;this.setState({numInitialRows: numInitialRows});const initialFirstVisibleRow = this.props.initialFirstVisibleRow ? this.props.initialFirstVisibleRow : 0;this.setState({initialFirstVisibleRow: initialFirstVisibleRow});this.setState({initialSelectedItems:this.props.initialSelectedItems});},componentDidMount() {},componentWillReceiveProps(props, state) {//Log.debug('GridTable will receive props:');//Log.debug(props);},componentWillUpdate(props, state) {//Log.debug('GridTable will update:');//Log.debug(props);},componentDidUpdate(prevProps, prevState) {//Log.debug('GridTable component did update');//make sure there's not another update in progress, as this breaks the gridApi call hereif(this.gridApi && !this.props.queryPaneCallback.isInProgress()){//Log.debug('calling refreshInfintePageCache');this.gridApi.refreshInfinitePageCache();}},getDefaultProps: function () {return {listContext: null,lastRefreshTime: null,initialSelectedItems: null,numInitialRows: CV_GRID_PAGE_SIZE,initialFirstVisibleRow: null,queryPaneCallback: null,searchNavResult: null,quickFilterCallback: null,eventRegistry: null,navigationListeners: [],actionListeners: [],gridListener: null,stateChangeListeners: []}},getInitialState: function () {return {numInitialRows: null, initialFirstVisibleRow: null, initialSelectedItems:null}},quickFilter(filterText:string) {//submit the quick searchconst quickFilterCallback:CvSearchPaneCallback = this.props.quickFilterCallback;const queryPaneCallback:CvQueryPaneCallback = this.props.queryPaneCallback;if (quickFilterCallback) {quickFilterCallback.reopenSearch((success, error)=> {if (error) {this.props.eventRegistry.publishError('quickFilter reopen failed with ' + ObjUtil.formatRecAttr(error));} else {quickFilterCallback.clearSearchValues();quickFilterCallback.setPropValue('keyword', filterText);//this is key - ag-grid must rebuild the grid instancethis.resetDataSource();quickFilterCallback.submitSearch((success, error)=> {if (error) {queryPaneCallback.refresh();this.props.eventRegistry.publishError('quickFilter error ' + ObjUtil.formatRecAttr(error));}});}});}},render: function () {const {listContext, queryPaneCallback, searchNavResult, navigationListeners, actionListeners, stateChangeListeners, eventRegistry} = this.props;const entityRecs:Array<EntityRec> = ArrayUtil.copy<EntityRec>(listContext.scroller.buffer);const hasBinaries = this._anyBinaries(listContext, entityRecs);return (<CvNavigation navigationResult={searchNavResult}><CvForm formContext={searchNavResult.navRequest}><CvSearchPane paneRef={0} initMode={CvInitMode.MANUAL} detailsRenderer={(cvContext:CvContext,entityRec:EntityRec, searchCallback:CvSearchPaneCallback)=> {const columnDefs = listContext.listDef.activeColumnDefs.map((columnDef:ColumnDef)=> {//@TODO - fully integrate custom filtering//filter: this._getFilterType(columnDef.propertyDef),//filterParams: {apply:true},//the grid doesn't allow '.' in key namesreturn {headerName: columnDef.heading,field: columnDef.name.replace('.', CvGridPanel_DOT_REPL),width: this._getColumnWidth(columnDef),cellRendererFramework: CvGridTableCell};});columnDefs[0].pinned = 'left';columnDefs[0].cellRendererFramework = CvGridTableCellColumn0;if(!this.dataSource) {this.dataSource = new CvGridDataSource(-1, listContext, searchCallback, queryPaneCallback,navigationListeners, actionListeners, stateChangeListeners, eventRegistry);} else {this.dataSource.update(listContext, searchCallback, queryPaneCallback,navigationListeners, actionListeners, stateChangeListeners, eventRegistry);}return (<div style={{height: 550}} className="ag-fresh"><AgGridReactonGridReady={this._onGridReady}showToolPanel={false}onRowSelected={this._onRowSelected}onRowDoubleClicked={this._onRowDoubleClicked}onBodyScroll={UIUtil.debounce(this._onBodyScroll, 200)}getRowStyle={this._getRowStyle}getRowNodeId={this._getRowNodeId}rowHeight={hasBinaries ? 50 : 25}columnDefs={columnDefs}enableServerSideSorting={true}enableServerSideFilter={false}suppressRowClickSelection="false"rowSelection="multiple"rowDeselection={true}enableColResize={true}enableSorting={false}enableFilter={false}groupHeaders={false}suppressCellSelection={true}debug={false}rowModelType='infinite'infiniteInitialRowCount={this.state.numInitialRows}paginationPageSize={this.state.numInitialRows}infiniteBlockSize={this.state.numInitialRows}maxConcurrentDatasourceRequests={1}sortingOrder={['asc','desc']}datasource={this.dataSource}paginationOverflowSize={CV_GRID_ROW_OVERFLOW_SIZE}/></div>);}}/></CvForm></CvNavigation>);},resetDataSource: function() {this.dataSource = null;},shouldComponentUpdate(nextProps, nextState) {/*NOTE:initialSelectedItems, numInitialRows, initialFirstVisibleRow are all unmanaged properties, meaningthat when they change, they are not synchronized with component state (we ignore them)They are simply changing URL params to be retained only for navigation or a refresh*//*This is an 'inclusive' change list - updates DO NOT happen by defaultDesired updates should be explicitly added here*///update only if we have new list dataif(this.props.queryPaneCallback && !this.props.queryPaneCallback.isInProgress()) {if (nextProps.lastRefreshTime) {if (this.props.lastRefreshTime) {if (nextProps.lastRefreshTime.getTime() > this.props.lastRefreshTime.getTime()) {return true;}} else {return true;}}}return false;},_anyBinaries: function (listContext:ListContext, entityRecs:Array<EntityRec>):boolean {return listContext.entityRecDef.propertyDefs.some(propDef=>propDef.isBinaryType) ||entityRecs.some(entityRec=>!!entityRec.imageName || entityRec.props.some(prop=>!!prop.imageName));},_onBodyScroll: function(event) {/*1) Report change in 'first visible row' (unmanaged parameter)*///seems to be the only option for approximating the first visible row. really need a better solutionconst firstInScrollBuffer = this.gridApi.getFirstRenderedRow();const rowNum = (firstInScrollBuffer >= (CV_GRID_VISIBLE_ROWS/2)) ? firstInScrollBuffer + CV_GRID_SCROLL_BUFFER_ROWS : firstInScrollBuffer;if(this.props.gridListener) this.props.gridListener({type: CvGridEventType.FIRST_VISIBLE_ROW_CHANGE_EVENT, eventObj:rowNum});},_onGridReady: function (params:any) {this.gridApi = params.api;this.columnApi = params.columnApi;//relying on this event to tell us when more pages have been loaded and add to the scroll bufferthis.gridApi.addEventListener('paginationChanged', this._onPaginationChanged)//relying on this event firing after rows are loaded and inserted (this seems to be the only indication)this.gridApi.addEventListener('scrollVisibilityChanged', this._onRowsInitialized);//uncomment this log all the ag-grid events to the console for debugging//this.gridApi.addGlobalListener((event)=>{ const e = event; Log.debug(e); });},_onPaginationChanged: function(event) {/** 1) Report change in total rows loaded (unmanaged param)*/const model = this.gridApi.getModel();if(model) {const rowsLoaded = this.props.listContext.scroller.buffer.length;//don't update if rowsLoaded hasn't actually changed (i.e. on the first load)if(this.state.numInitialRows != rowsLoaded) {if(this.props.gridListener && (rowsLoaded > CV_GRID_PAGE_SIZE)) {this.props.gridListener({type: CvGridEventType.TOTAL_ROWS_LOADED_EVENT, eventObj: rowsLoaded});}}}},_onRowDoubleClicked: function (event) {event.node.data.rowCallback.fireAction();},_onRowSelected: function (event) {/*1) Report change in selections (unmanaged parameter)*///get the oids of the selected rows and notify the gridListeners fo the selectionif (event.node.data && event.node.data.entityRec) {const selectedItems = this.gridApi.getSelectedRows().map(data => data.entityRec.objectId);if (this.props.gridListener) this.props.gridListener({type: CvGridEventType.SELECTION_EVENT, eventObj:selectedItems});}},_onRowsInitialized: function(event) {//set the first visible row if specifiedif(this.state.initialFirstVisibleRow) {this.gridApi.ensureIndexVisible(this.state.initialFirstVisibleRow);}//select initial rows based on the supplied selectedItems oidsconst selectedItems = this.state.initialSelectedItems;if(selectedItems && selectedItems.length > 0){selectedItems.forEach(selectedItem=>{this.gridApi.forEachNode(node=>{if (node.data && node.data.entityRec &&(node.data.entityRec.objectId === selectedItem)) {node.setSelected(true);}});});}//remove this listener as we only want this to fire on the first loadthis.gridApi.removeEventListener('scrollVisibilityChanged', this._onRowsInitialized);},_getFilterType: function (propDef:PropDef) {if (propDef.isDateType || propDef.isDateTimeType) {return 'date';} else if (propDef.isNumericType) {return 'number'} else {return 'text';}},_getRowStyle: function (params) {if (params.data && params.data.entityRec) {const styleInfo:CvDataAnnoStyle = (CvDataAnno as any).generateStyleInfo(params.data.entityRec);return styleInfo.cssStyle;} else {return null;}},_getRowNodeId: function (data) {return data.entityRec.objectId;},_getColumnWidth: function (columnDef:ColumnDef) {return columnDef.propertyDef.presLength < 200 || columnDef.propertyDef.presLength > 2000 ? 250 : columnDef.propertyDef.presLength;},})

CvGridTableCell

CvGridTableCell: ClassicComponentClass<__type> = React.createClass<{},{}>({render: function () {return this.props.value || null;}})

CvGridTableCellColumn0

CvGridTableCellColumn0: ClassicComponentClass<__type> = React.createClass<{},{}>({render: function () {if (this.props.data) {return this.props.value || null;} else {return <i className="fa fa-spinner fa-pulse cv-table-spinner-size"/>;}}})

CvQuickFilter

CvQuickFilter: ClassicComponentClass<object> = React.createClass<{filterValueListener:CvValueListener<string>}, {searchText:string, isSet:boolean}>({getDefaultProps: function () {return {filterValueListener: null}},getInitialState: function () {return {searchText: "", isSet:false}},isSet: function() {return this.state.searchText;},render: function () {return <span className="form-inline cv-quick-filter"><input placeholder="Quick Filter..." className="form-control" type="text" value={this.state.searchText}onChange={this._onFilterTextChange} onKeyUp={this._filterKeyUp}/><button className="btn btn-default" onClick={this.resetText} title="Reset Quick Filter"><span className="glyphicon glyphicon-remove-sign" aria-hidden="true"/></button></span>},resetText() {this.setState({searchText: ""});const listener:CvValueListener<string> = this.props.filterValueListener;if (listener) {listener("");}},_filterKeyUp(e:any) {if (e.keyCode === 13) {const listener:CvValueListener<string> = this.props.filterValueListener;if (listener) {listener(this.state.searchText);}}},_onFilterTextChange(e:any) {const value = e.target.value ? e.target.value : "";this.setState({searchText: value});}})

Generated using TypeDoc