interface ExistingProject { id : string ; name : string ; description : string ; systemId : string ; } type NewProjectResult = { project : { name : string ; description : string ; systemId : string ; icon : File ; } ; open : boolean ; } ; export interface SystemsData { [ value ] : string [ ] ; } export default class CreateOrEditProjectDialog extends SupClient . Dialogs . BaseDialog < NewProjectResult > { private systemsById : SystemsData ; private nameInputElt : HTMLInputElement ; private descriptionInputElt : HTMLTextAreaElement ; private iconInputElt : HTMLInputElement ; private projectType : { systemId : string ; templateName : string ; } ; private projectTypeSelectElt : HTMLSelectElement ; private systemDescriptionElt : HTMLDivElement ; private templateDescriptionElt : HTMLDivElement ; private iconFile : File = null ; private iconElt : HTMLImageElement ; private existingProject : ExistingProject ; private openCheckboxElt : HTMLInputElement ; constructor ( systemsById , options , callback ) { super ( callback ) ; this . systemsById = systemsById ; if ( options == null ) options = { } ; if ( options . autoOpen == null ) options . autoOpen = true ; this . existingProject = options . existingProject ; SupClient . html ( "div" , "group" , { parent : this . formElt , textContent : SupClient . i18n . t ( this . existingProject == null ? "hub:newProject.prompt" : "hub:editDetails.prompt" ) } ) ; const containerElt = SupClient . html ( "div" , "group" , { parent : this . formElt , style : { display : "flex" } } ) ; this . iconInputElt = SupClient . html ( "input" , { type : "file" , hidden : true , accept : "image/png" , parent : containerElt } ) ; const iconButtonElt = SupClient . html ( "button" , { type : "button" , parent : containerElt , style : { cursor : "pointer" , background : "transparent" , width : "72px" , height : "72px" , margin : "0" , padding : "0" , border : "0" , fontSize : "0" } } ) ; iconButtonElt . addEventListener ( "click" , ( ) => this . iconInputElt . click ( ) ) ; const iconSrc = options . existingProject == null ? "/images/default-project-icon.png" : ( `/projects/${ options . existingProject . id }/icon.png` ) ; this . iconElt = SupClient . html ( "img" , { src : iconSrc , draggable : false , parent : iconButtonElt , style : { width : "72px" , height : "72px" , border : "1px solid rgba(0,0,0,0.2)" , borderRadius : "4px" , background : "#eee" } } ) ; this . iconInputElt . addEventListener ( "change" , this . onIconChange ) ; const textContainerElt = SupClient . html ( "div" , { parent : containerElt } ) ; textContainerElt . style . flex = "1" ; textContainerElt . style . display = "flex" ; textContainerElt . style . flexFlow = "column" ; textContainerElt . style . marginLeft = "0.5em" ; this . nameInputElt = SupClient . html ( "input" , { parent : textContainerElt , required : true , placeholder : SupClient . i18n . t ( "hub:newProject.namePlaceholder" ) , pattern : SupClient . namePattern , title : SupClient . i18n . t ( "common:namePatternDescription" ) } ) ; this . nameInputElt . style . marginBottom = "0.5em" ; this . descriptionInputElt = SupClient . html ( "textarea" , { parent : textContainerElt , placeholder : SupClient . i18n . t ( "hub:newProject.descriptionPlaceholder" ) , style : { flex : "1" , resize : "none" } } ) ; this . descriptionInputElt . addEventListener ( "keypress" , this . onFieldKeyDown ) ; const downElt = SupClient . html ( "div" , { style : { display : "flex" , alignItems : "center" } } ) ; if ( options . existingProject == null ) { this . projectTypeSelectElt = SupClient . html ( "select" , { parent : this . formElt , style : { marginBottom : "0.5em" } } ) ; for ( const systemId in this . systemsById ) { const systemInfo = this . systemsById [ systemId ] ; const optGroupElt = SupClient . html ( "optgroup" , { parent : this . projectTypeSelectElt , label : SupClient . i18n . t ( `system-${ systemId }:title` ) } ) ; SupClient . html ( "option" , { parent : optGroupElt , value : `${ systemId }.empty` , textContent : SupClient . i18n . t ( "hub:newProject.emptyProject.title" ) } ) ; for ( const templateName of systemInfo ) { SupClient . html ( "option" , { parent : optGroupElt , value : `${ systemId }.${ templateName }` , textContent : SupClient . i18n . t ( `${ systemId }-${ templateName }:title` ) } ) ; } } const descriptionContainerElt = SupClient . html ( "div" , { parent : this . formElt , style : { backgroundColor : "#eee" , border : "1px solid #ccc" , padding : "0.5em" , color : "#444" , marginBottom : "0.5em" } } ) ; this . templateDescriptionElt = SupClient . html ( "div" , "template-description" , { parent : descriptionContainerElt } ) ; this . systemDescriptionElt = SupClient . html ( "div" , "system-description" , { parent : descriptionContainerElt } ) ; this . onProjectTypeChange ( ) ; this . openCheckboxElt = SupClient . html ( "input" , { parent : downElt , type : "checkbox" , id : "auto-open-checkbox" , checked : options . autoOpen , style : { margin : "0 0.5em 0 0" } } ) ; SupClient . html ( "label" , { parent : downElt , textContent : SupClient . i18n . t ( "hub:newProject.autoOpen" ) , htmlFor : "auto-open-checkbox" , style : { flex : "1" , margin : "0" } } ) ; } this . formElt . appendChild ( downElt ) ; const buttonsElt = SupClient . html ( "div" , "buttons" , { parent : downElt } ) ; if ( options . existingProject != null ) buttonsElt . style . flex = "1" ; buttonsElt . className = "buttons" ; const cancelButtonElt = SupClient . html ( "button" , "cancel-button" , { parent : buttonsElt , type : "button" , textContent : SupClient . i18n . t ( "common:actions.cancel" ) } ) ; cancelButtonElt . addEventListener ( "click" , ( event ) => { event . preventDefault ( ) ; this . cancel ( ) ; } ) ; this . validateButtonElt = SupClient . html ( "button" , "validate-button" , { textContent : SupClient . i18n . t ( options . existingProject == null ? "common:actions.create" : "common:actions.update" ) , } ) ; if ( navigator . platform === "Win32" ) buttonsElt . insertBefore ( this . validateButtonElt , cancelButtonElt ) ; else buttonsElt . appendChild ( this . validateButtonElt ) ; if ( options . existingProject != null ) { this . nameInputElt . value = options . existingProject . name ; this . descriptionInputElt . value = options . existingProject . description ; } else { this . projectTypeSelectElt . addEventListener ( "change" , this . onProjectTypeChange ) ; this . projectTypeSelectElt . addEventListener ( "keydown" , this . onFieldKeyDown ) ; } this . nameInputElt . focus ( ) ; } submit ( ) { let systemId = null ; let templateName = null ; if ( this . projectTypeSelectElt != null ) [ systemId , templateName ] = this . projectTypeSelectElt . value . split ( "." ) ; const project = { name : this . nameInputElt . value , description : this . descriptionInputElt . value , systemId , template : templateName !== "empty" ? templateName : null , icon : this . iconFile } ; super . submit ( { project , open : ( this . openCheckboxElt != null ) ? this . openCheckboxElt . checked : null } ) ; } private onIconChange = ( event ) => { if ( this . iconInputElt . files . length === 0 ) { this . iconFile = null ; if ( this . existingProject == null ) this . iconElt . src = "/images/default-project-icon.png" ; else this . iconElt . src = `/projects/${ this . existingProject . id }/icon.png` ; } else { this . iconFile = this . iconInputElt . files [ 0 ] ; const reader = new FileReader ( ) ; reader . addEventListener ( "load" , ( event ) => { this . iconElt . src = ( event . target as any ) . result ; } ) ; reader . readAsDataURL ( this . iconFile ) ; } } ; private onFieldKeyDown = ( event ) => { if ( event . keyCode === 13 ) { event . preventDefault ( ) ; this . submit ( ) ; } } ; private onProjectTypeChange = ( ) => { if ( this . projectType != null ) { const path = `${ this . projectType . systemId }.${ this . projectType . templateName }` ; const oldOptionElt = this . projectTypeSelectElt . querySelector ( `option[value="${ path }"]` ) ; const oldTemplate = this . getTemplate ( this . projectType . systemId , this . projectType . templateName ) ; oldOptionElt . textContent = oldTemplate . title ; } const [ systemId , templateName ] = this . projectTypeSelectElt . value . split ( "." ) ; this . projectType = { systemId , templateName } ; const template = this . getTemplate ( systemId , templateName ) ; const systemTitle = SupClient . i18n . t ( `system-${ systemId }:title` ) ; this . projectTypeSelectElt . querySelector ( "option:checked" ) . textContent = `${ systemTitle } — ${ template . title }` ; this . templateDescriptionElt . textContent = template . description ; const systemDescription = SupClient . i18n . t ( `system-${ systemId }:description` ) ; this . systemDescriptionElt . textContent = systemDescription ; if ( systemDescription . length === 0 && template . description . length === 0 ) { this . systemDescriptionElt . textContent = "(No description provided)" ; } } ; private getTemplate ( systemId , templateName ) { if ( templateName !== "empty" ) { return { title : SupClient . i18n . t ( `${ systemId }-${ templateName }:title` ) , description : SupClient . i18n . t ( `${ systemId }-${ templateName }:description` ) } ; } return { title : SupClient . i18n . t ( "hub:newProject.emptyProject.title" ) , description : SupClient . i18n . t ( "hub:newProject.emptyProject.description" ) } ; } }