/** * Created by rburson on 3/21/16. */ import * as React from 'react' import { CvState, CvProps, CvBaseMixin, CvDetailsPaneCallback, CvEvent, CvEventType, CvMessage, CvMessageType, CvValueAdapter, CvValueListener, CvImageExistenceState, CvImageAction, CvImagePackage, CvImagePackageUrl, CvImageProducer } from 'catreact' import { CvDataAnno, CvDataAnnoStyle, CvHtmlProp } from './catreact-html' import { ArrayUtil, Try, Prop, PropDef, DetailsContext, CellValueDef, AttributeCellValueDef, LabelCellValueDef, ForcedLineCellValueDef, SubstitutionCellValueDef, TabCellValueDef, Log, PropFormatter, CodeRef, ObjectRef, ObjUtil, TimeValue, EditorContext, Attachment, Binary } from 'catavolt-sdk' import SyntheticEvent = React.SyntheticEvent; /* * -------- Start react-widgets setup ----------- * The following are all the requirements for using the react-widgets dateTime components * globalize is required and a configured 'instance' must be provided to react-widgets * Note: These all use the older, commonjs-style object export * On the bright side, globalize is very comprehensive, so supporting different locales and formats * of numbers, currency, and dates in the future should be easier */ import {DateTimePicker, DropdownList, Multiselect} from 'react-widgets'; import Globalize = require('globalize') //import the localization data import cldrDataSubtags = require( "cldr-data/supplemental/likelySubtags" ); import cldrDataTime = require( "cldr-data/supplemental/timeData" ); import cldrDataWeek = require( "cldr-data/supplemental/weekData" ); //English import cldrDataNumSystems = require( "cldr-data/supplemental/numberingSystems" ); import cldrDataGreg = require( "cldr-data/main/en/ca-gregorian" ); import cldrDataTimeZoneNames = require( "cldr-data/main/en/timeZoneNames" ); import cldrDataDate = require( "cldr-data/main/en/dateFields" ); import cldrDataNumber = require( "cldr-data/main/en/numbers" ); //German import cldrDataGregDE = require( "cldr-data/main/de/ca-gregorian" ); import cldrDataTimeZoneNamesDE = require( "cldr-data/main/de/timeZoneNames" ); import cldrDataDateDE = require( "cldr-data/main/de/dateFields" ); import cldrDataNumberDE = require( "cldr-data/main/de/numbers" ); Globalize.load(cldrDataDate, cldrDataGreg, cldrDataNumber, cldrDataGregDE, cldrDataTimeZoneNamesDE, cldrDataDateDE, cldrDataNumberDE, cldrDataTime, cldrDataWeek, cldrDataSubtags, cldrDataTimeZoneNames, cldrDataNumSystems); //Set the locale here Globalize.locale('en') import globalizeLocalizer = require('react-widgets-globalize') globalizeLocalizer(Globalize); /* * -------- End react-widgets setup ---------- */ import * as moment from 'moment'; export interface CvCellValueDefState extends CvState { } export interface CvCellValueDefProps extends CvProps { cellValueDef:CellValueDef; detailsContext?:EditorContext; detailsCallback?:CvDetailsPaneCallback; imageProducers?:Array; imageReadOnly?:boolean, wrapperElem:any; wrapperElemProps?:any; overrideDefaultValue?:string; valueChangeListener?:(propName:string, propDef:PropDef, newValue:any)=>void; } export let CvCellValueDefMixin = { _applyHeaderStyle(component:any, cellValueDef:CellValueDef): any { let answer = component; if (cellValueDef.isHeading1Style) { answer =

{component}

; } else if (cellValueDef.isHeading2Style) { answer =

{component}

; } else if (cellValueDef.isHeading3Style) { answer =

{component}

; } else if (cellValueDef.isHeading4Style) { answer =

{component}

; } return answer; }, cellValueDef: function (nextProps) { return (nextProps && nextProps.cellValueDef) || this.props.cellValueDef; }, detailsCallback: function (nextProps) { return (nextProps && nextProps.detailsCallback) || this.props.detailsCallback; }, detailsContext: function (nextProps) { return (nextProps && nextProps.detailsContext) || this.props.detailsContext || this.firstInScope(DetailsContext); }, getChildContext: function () { const ctx = this.getDefaultChildContext(); ctx.cvContext.scopeCtx.scopeObj = this.cellValueDef(); return ctx; } }; /* *************************************************** * Render an CellValueDef *************************************************** */ export let CvCellValueDef = React.createClass({ mixins: [CvBaseMixin, CvCellValueDefMixin], render: function () { if (this.props.renderer) { return this.props.renderer(this.getChildContext().cvContext); } else { const detailsContext:DetailsContext = this.detailsContext(); const cellValueDef:CellValueDef = this.cellValueDef(); let component = null; if (cellValueDef) { if (cellValueDef instanceof AttributeCellValueDef) { const prop = detailsContext.entityRec.propAtName((cellValueDef as AttributeCellValueDef).propertyName); const hasFocus = detailsContext.detailsDef.focusPropName ? (cellValueDef as AttributeCellValueDef).propertyName == detailsContext.detailsDef.focusPropName : false; const styleInfo:CvDataAnnoStyle = (CvDataAnno as any).generateStyleInfo(prop); component = return component; } else if (cellValueDef instanceof LabelCellValueDef) { component = {(cellValueDef as LabelCellValueDef).value} // Apply the heading style component = this._applyHeaderStyle(component, cellValueDef); } else if (cellValueDef instanceof ForcedLineCellValueDef) { // Display a hidden M to make sure this line takes up some vertical space. component = {'M'} } else if (cellValueDef instanceof TabCellValueDef) { component = } else if (cellValueDef instanceof SubstitutionCellValueDef) { component = {(cellValueDef as SubstitutionCellValueDef).value} } else { component = } } const props = ObjUtil.addAllProps(this.props.wrapperElemProps, {}); return React.createElement(this.props.wrapperElem, props, component); } } }); /* *************************************************** * Render an AttributeCellValueDef *************************************************** */ export interface CvAttributeCellValueDefState extends CvCellValueDefState { availableValues?:Array; selectedImageSrc?:string; imageExistenceState:CvImageExistenceState; imageUndoData: any; } export interface CvAttributeCellValueDefProps extends CvProps { cellValueDef:CellValueDef; detailsContext?:EditorContext; detailsCallback?:CvDetailsPaneCallback; imageProducers?:Array; imageReadOnly?:boolean, inlineStyle?:{}; overrideText?:string; overrideDefaultValue?:string; valueChangeListener?:(propName:string, propDef:PropDef, newValue:any)=>void; classSelector?:(propDef:PropDef, defaultClass?:string)=>string; hasFocus?:boolean; } const cv_no_selection_value:string = 'cv_no_selection_value'; export let CvAttributeCellValueDef = React.createClass({ mixins: [CvBaseMixin, CvCellValueDefMixin], componentWillMount: function () { this.refresh(); }, componentWillReceiveProps: function (nextProps) { this.refresh(nextProps); }, getDefaultProps: function () { return {cellValueDef: null, detailsContext: null, detailsCallback: null, overrideText: null, overrideDefaultValue: null, valueChangeListener:null, classSelector:null, hasFocus:false } }, getInitialState: function () { return {availableValues: null, imageExistenceState: null} }, render: function () { const csf = this.props.classSelector ? this.props.classSelector : (propDef:PropDef, defaultClass?:string):string => { return defaultClass } const inlineStyle = this.props.inlineStyle; if (this.props.renderer) { return this.props.renderer(this.getChildContext().cvContext); } else { const detailsContext = this.detailsContext(); const cellValueDef:AttributeCellValueDef = this.cellValueDef(); const overrideDefaultValue = this.props.overrideDefaultValue; const focusFn = (ref)=>{ if(ref && this.props.hasFocus) ref.focus(); } let component = null; if (cellValueDef && cellValueDef.propertyName) { if (!detailsContext.isReadModeFor(cellValueDef.propertyName) && !this.props.overrideText) { const prop:Prop = detailsContext.buffer.propAtName(cellValueDef.propertyName); const propDef:PropDef = detailsContext.entityRecDef.propDefAtName(cellValueDef.propertyName); if (prop) { /*** Combobox ***/ if (cellValueDef.isComboBoxEntryMethod) { if (this.state.availableValues) { //this is not applied atm const cn = csf(propDef,"form-control cv-cell-def-select-box"); const data:{selected:any, values:Array} = this._assignData(overrideDefaultValue, prop.value, propDef, this.state.availableValues); component = this._getOptionDisplayValue(item, propDef)) as any} onChange={this._propChange.bind(this, prop.name, propDef)} ref={focusFn}/> } /*** Dropdown ***/ } else if (cellValueDef.isDropDownEntryMethod) { if (this.state.availableValues) { if(propDef.isListType) { component = } else { //this is not applied atm const cn = csf(propDef,"form-control cv-cell-def-select-box"); const data:{selected:any, values:Array} = this._assignData(overrideDefaultValue, prop.value, propDef, this.state.availableValues); component = this._getOptionDisplayValue(item, propDef)) as any} onChange={this._propChange.bind(this, prop.name, propDef)} ref={focusFn}/> } } /*** Icon chooser ***/ } else if (cellValueDef.isIconEntryMethod) { if (this.state.availableValues) { const data:{selected:any, values:Array} = this._assignData(null, prop.value, propDef, this.state.availableValues); component = } } else { /*** Binary ***/ if (detailsContext.isBinary(cellValueDef)) { const imageActions:Array = this.props.imageProducers == null ? null : this.props.imageProducers.filter(ip=> { return (this.state.imageExistenceState == CvImageExistenceState.Present && ip.includeWhenImageisPresent) || (this.state.imageExistenceState == CvImageExistenceState.Missing && ip.includeWhenImageIsMissing) || (this.state.imageExistenceState == CvImageExistenceState.Deleted && ip.includeWhenImageIsDeleted); }).map(w=>{ let ip:CvImageProducer = w as CvImageProducer; let launchPick = ()=> { let input:HTMLInputElement = this.refs["inputFileRef"] as HTMLInputElement; input.click(); }; let a:CvValueAdapter = new CvValueAdapter(); let f = this.setImageFromDataUrl.bind(this, prop.name, propDef, launchPick); a.subscribe((v:Object)=>{ f(v) }); return { callback:()=>{ ip.prodImageCB(a.createValueListener())}, buttonClassName:ip.buttonClassName}; }); const style = this.props.inlineStyle ? this.props.inlineStyle : (this.props.imageStyle ? this.props.imageStyle : this.props.style); const readOnly = (this.props.imageReadOnly === undefined) || (this.props.imageReadOnly === null) ? false : this.props.imageReadOnly; component =
} else { /*** Boolean ***/ if (propDef.isBooleanType) { component = /*** Datetime ***/ } else if (propDef.isDateTimeType) { const formatter = Globalize.dateFormatter({datetime:"medium"}); const editFormatter = Globalize.dateFormatter({datetime:"short"}); const timeFormatter = Globalize.dateFormatter({time:"medium"}); component = { return moment(str).toDate()}} ref={focusFn}/> /*** Date ***/ } else if (propDef.isDateType) { const formatter = Globalize.dateFormatter({date:"long"}); const editFormatter = Globalize.dateFormatter({date:"short"}); component = { return moment(strDate).toDate()}} ref={focusFn}/> /*** Time ***/ } else if (propDef.isTimeType) { const formatter = Globalize.dateFormatter({time:"medium"}); const editFormatter = Globalize.dateFormatter({time:"medium"}); component = { return moment("2000-01-01 " + strTime, ["YYYY-MM-DD h:m:s:a", "YYYY-MM-DD H:m:s"]).toDate()}} ref={focusFn}/> } else if(propDef.isFileAttachment) { component = /*** Text ***/ } else if(propDef.isTextBlock) { const cn = csf(propDef, "form-control"); component =